Easy Session Testing in Phoenix and Plug

1 minute read

Many real world Phoenix applications use JWTs to handle authentication, but there are situations that still require being able to test session. This has traditionally been tedious in Elixir (see below). However, Plug has recently added functionality to make this very simple. It’s a relatively new feature and not very well documented online. While it is in the Plug docs, it is not in the Phoenix guides or most online resources. The only place I’ve seen it referenced is far down a Github issue.

Plug.Test.init_test_session(conn, current_user_id: 1)

That’s it!

There are a couple ways to utilize this. Let’s take an autogenerated controller test:

describe "index" do
  test "lists all users", %{conn: conn} do
    conn = get conn, admin_user_path(conn, :index)
    assert html_response(conn, 200) =~ "Listing Users"
  end
end

To set session just for this test, we just have to add one line:

describe "index" do
  test "lists all users", %{conn: conn} do
    # this could be streamlined using pipes |>
    conn = Plug.Test.init_test_session(conn, current_user_id: 1)
    conn = get conn, admin_user_path(conn, :index)
    assert html_response(conn, 200) =~ "Listing Users"
  end
end

If we wanted to set a session value for an entire set of controller tests, that’s simple too. We just need to add one block in the test:

defmodule MyAppWeb.UserControllerTest do
  use MyAppWeb.ConnCase
  alias MyApp.User

  # ... add the following block:

  setup %{conn: conn} do
    conn = conn
      |> Plug.Test.init_test_session(current_user_id: 1)
    {:ok, conn: conn}
  end
  # ... rest of tests will now have that session value
end

Now, the conn struct used for all the tests will have current_user_id: 1 set in session, as expected. This is a huge improvement, since it removes the complexity and ambiguity of previous ways to accomplish testing session data.

Older approaches

There are quite a few older approaches, most of which are more complex approaches which may not work in all situations. Typically, they require either customizing the conn used in tests or by using tags paired with custom connection setup. Sometimes, this includes bypassing pipelines. There are other ways which include tweaking your app’s pipelines(1, 2) and setting current_user directly.

To be clear, all of these approaches work, and have been necessary in the past. But luckily, Plug 1.5 added made this all much simpler.