0
votes

I am struggling at testing api endpoint which requires token header. The idea is to test two cases, with and without authentication token.

I've come up with the following working solution, but it feels somewhat clumsy to me.

  defmodule MyApi.SecretControllerTest do
    use MyApi.ConnCase

    alias MyApi.{Repo, User, Session}

    setup %{conn: conn} do
      user = create_user(%{name: "john"})
      session = create_session(user)

      conn = conn
      |> put_req_header("accept", "application/json")
      |> put_req_header("authorization", "Bearer " <> session.token)
      {:ok, conn: conn}
    end

    def create_user(%{name: name}) do
      User.changeset(%User{}, %{email: "#{name}@gmail.com"})
      |> Repo.insert!
    end

    def create_session(user) do
      Session.create_changeset(%Session{user_id: user.id}, %{})
      |> Repo.insert!
    end

    test "returns 401 error when user is not authenticated" do
      conn = get build_conn, "/api/secrets"
      assert json_response(conn, 401)["error"] != %{}
    end

    test "renders secret resource when user is authenticated", %{conn: conn} do
      conn = get conn, secret_path(conn, :index)
      assert json_response(conn, 200)["message"] != %{}
    end
  end
1
Welcome to stackoverflow! Your code seems to work as you expect, so there's not much we can do here. If you really think something is wrong try to explain the expected behaviour/outcome in the question.Paweł Obrok
Yes, i know that this code is working as expected, i'm asking if there is more convenient way to test this sort of things. Actually the test for 401 error is especially ugly, because i don't know how to manage this not avoiding connection setup.Slyfest
@Slyfest what authentication library are you using for your app? There's a slightly better way to do it, but applies only if you're using Guardian, hence my question.Svilen

1 Answers

2
votes

If you're using Guardian for authentication, and the endpoint is an API one (e.g. going through an :api pipeline) you can use the api_sign_in helper method, that doesn't rely on an existing session (so you can remove that session-related code).

Here's an example of putting the "sign in" logic into a test tag, that you can apply to the tests that require a logged in user:

  setup %{conn: conn} = config do
    cond do
      config[:login] ->
        user = insert_user()
        signed_conn = Guardian.Plug.api_sign_in(conn, user)
        {:ok, conn: signed_conn}
      true ->
        :ok
    end
  end

  @tag :login
  test "shows page only when logged in", %{conn: conn} do
    conn = get(conn, some_page_path(conn, :index))
    assert html_response(conn, 200)
  end