Sign in user with ExUnit tag
Let’s say that you have a JSON API with token based authentication. Such an app is described in this great tutorial.
Now you want to be able to easily tag a particular test and run it within a context where a user is signed in.
In order to achieve this you can use ExUnit’s tags.
Let’s take the controller test from the tutorial and tag it:
defmodule TodoApi.TodoControllerTest do
use TodoApi.ConnCase
alias TodoApi.Todo
alias TodoApi.User
alias TodoApi.Session
@valid_attrs %{complete: true, description: "some content"}
setup %{conn: conn, current_user: current_user} do #MIND THE NEW KEY
{:ok,
conn: put_req_header(conn, "accept", "application/json"),
current_user: user }
end
@tag signed_in: "jane" #THE TAG
test "creates and renders resource when data is valid", %{conn: conn, current_user: current_user} do
conn = post conn, todo_path(conn, :create), todo: @valid_attrs
assert json_response(conn, 201)["data"]["id"]
todo = Repo.get_by(Todo, @valid_attrs)
assert todo
assert todo.owner_id == current_user.id
end
test "renders 401", %{conn: conn} do
conn = post conn, todo_path(conn, :create), todo: @valid_attrs
assert json_response(conn, 401)
todo = Repo.get_by(Todo, @valid_attrs)
refute todo
end
end
We’ve used @tag signed_in: "jane"
to tag the test. Also observe that the setup
method now pattern matches on :current_user
key. This key/value will be return by the setup
method defined in test/support/conn_case.ex
. It can look like that:
defmodule TodoApi.ConnCase do
# ...
# deleted for brevity
# ...
def create_user(%{name: name}) do
User.changeset(%User{}, %{email: "#{name}@example.com"}) |> Repo.insert!
end
def create_session(user) do
Session.create_changeset(%Session{user_id: user.id}, %{}) |> Repo.insert!
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(TodoApi.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(TodoApi.Repo, {:shared, self()})
end
conn = Phoenix.ConnTest.build_conn()
if tags[:signed_in] do
user = create_user(tags[:signed_in])
session = create_session(user)
conn = Plug.Conn.put_req_header(conn,
"authorization", "Token token=\"#{session.token}\"")
{:ok, conn: conn, current_user: user}
else
{:ok, conn: conn, current_user: nil}
end
end
end