How to do Phoenix.Token.sign in tests?

Hi guys, elixir/phoenix beginner here.

I added auth verification to my app and put one url under it.
I have this test:

describe "can get user details" do
    setup [:login_current_user]

    test "render user details", %{conn: conn, user: user} do
      conn = get(conn, Routes.user_path(conn, :show, user))
      assert response(conn, 200)

      assert %{
               "id" => id,
               "email" => email,
               "is_active" => true
             } = json_response(conn, 200)
    end
  end

login_current_user creates a user and a token via Phoenix.Token.sign and fails due to secret_key_base being nil.

I added secret_key_base under MyAppWeb.Endpoint (in config/test.ex), but it doesn’t help. The test still fails with
** (FunctionClauseError) no function clause matching in Phoenix.Token.get_key_base/1
and I still see secret_key_base is nil (in the traceback).

This is the code in login_current_user:

defp setup_current_user(conn) do
    user = fixture(:current_user)

    {:ok, session} =
      Auth.create_session(%{
        user_id: user.id,
        token:
          Phoenix.Token.sign(
            conn,
            Application.get_env(:my_app, MyAppWeb.Endpoint)[:salt],
            user.id
          )
      })

    {
      :ok,
      conn: Test.init_test_session(conn, current_user_id: user.id),
      current_user: user,
      token: session.token
    }
  end

  defp login_current_user(conn) do
    {:ok, conn: conn, current_user: current_user, token: token} = setup_current_user(conn)

    conn
    |> put_req_header("accept", "application/json")
    |> put_req_header("authorization", "Token #{token}")

    {:ok, conn: conn, current_user: current_user}
  end

What am i doing wrong? How to make it work? :pray:

Are you sure this is Plug.Conn that is passed to login_current_user ?
I think this is a context containing conn: %Plug.Conn{}. I would suggest to inspect the param of :login_current_user and pass proper %Plug.Conn{} to Phoenix.Token.sign.

You are right. I tried IO.inspect and it is not the %Plug.conn{}. I got that fixed but now im getting another error:
key :phoenix_endpoint not found in %{phoenix_recycled: true, plug_skip_csrf_protection: true}

I guess im still missing something about test configs.

Ok, I got it working. Following this github issue https://github.com/phoenixframework/phoenix/issues/1650,
I changed my code to this:

defp setup_current_user(conn) do
    user = fixture(:current_user)

    {:ok, session} =
      Auth.create_session(%{
        user_id: user.id,
        token:
          Phoenix.Token.sign(
            MyAppWeb.Endpoint,
            Application.get_env(:my_app, MyAppWeb.Endpoint)[:salt],
            user.id
          )
      })

    {
      :ok,
      conn: Test.init_test_session(conn, current_user_id: user.id),
      current_user: user,
      token: session.token
    }
  end

Note, I am passing MyAppWeb.Endpoint instead of %Plug.Conn{}.

Which lead me to find out that silly me was modifying the connection without saving the updated version and passing that to the test. So I also had to fix the :login_current_user to this:

defp login_current_user(conn) do
    {:ok, conn: conn, current_user: current_user, token: token} = setup_current_user(conn)

    updated_conn = 
      conn
      |> put_req_header("accept", "application/json")
      |> put_req_header("authorization", "Token #{token}")

    {:ok, conn: updated_conn, current_user: current_user}
  end

Now it all works :slight_smile: