In my Phoenix app I have Plug that looks like this:
defmodule MyApp.Web.Plugs.RequireAuth do
import Plug.Conn
import Phoenix.Controller
import MyApp.Web.Router.Helpers
def init(_options) do
end
def call(conn, _options) do
if conn.assigns[:user] do
conn
else
conn
|> put_flash(:error, "You must be logged in")
|> redirect(to: project_path(conn, :index))
|> halt()
end
end
end
I wrote tests for it:
defmodule MyApp.Web.Plugs.RequireAuthTest do
use MyApp.Web.ConnCase
import MyApp.Web.Router.Helpers
alias MyApp.Web.Plugs.RequireAuth
alias MyApp.Accounts.User
setup do
conn = build_conn()
{:ok, conn: conn}
end
test "user is redirected when current user is not set", %{conn: conn} do
conn = RequireAuth.call(conn, %{})
assert redirected_to(conn) == project_path(conn, :index)
end
test "user is not redirected when current user is preset", %{conn: conn} do
conn = conn
|> assign(:user, %User{})
|> RequireAuth.call(%{})
assert conn.status != 302
end
end
When I run my specs it returns me following error:
1) test user is redirected when current user is not set (MyApp.Web.Plugs.RequireAuthTest)
test/lib/web/plugs/require_auth_test.exs:15
** (ArgumentError) flash not fetched, call fetch_flash/2
stacktrace:
(phoenix) lib/phoenix/controller.ex:1231: Phoenix.Controller.get_flash/1
(phoenix) lib/phoenix/controller.ex:1213: Phoenix.Controller.put_flash/3
(my_app) lib/my_app/web/plugs/require_auth.ex:14: MyApp.Web.Plugs.RequireAuth.call/2
test/lib/web/plugs/require_auth_test.exs:16: (test)
When I remove this line from my plug:
put_flash(:error, "You must be logged in")
spec are passing without problems. What I'm doing wrong?
Your example is described in Programming Phoenix and solution for that is to bypass the router layer with bypass_through/3 from Phoenix.ConnTest.
Use something like this in your test suite:
setup %{conn: conn} do
conn =
conn
|> bypass_through(Rumbl.Router, :browser)
|> get("/")
{:ok, %{conn: conn}}
end
It will give you valid flash and session support.