Following redirection in ControllerTests

plug
phoenix
exunit
Tags: #<Tag:0x00007f8ec02be7a0> #<Tag:0x00007f8ec02bdda0> #<Tag:0x00007f8ec02bd440>

#1

Say I have a controller like so.

  def create_pass_reset(conn, %{"user" => %{"email" => email}}) do
    case Accounts.reset_pass(email) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "Password Reset Sent to #{user.email}")
        |> redirect(to: session_path(conn, :new))
...
    end
  end

Note that I am setting a flash on a conn that is due to be redirected.

And say I have a test like so.

test "POST /password-reset", %{conn: conn, user: user} do
  conn = post conn, user_path(conn, :create_pass_reset, %{"user" => %{"email" => user.email}})
  assert redirected_to(conn, 302) =~ "/login"
  assert html_response(conn, 302) ==  "Password Reset Sent to #{user.email}"
end

Well clearly the issue with this test is that the conn does not contain the state after the redirection occurred and thus does not have the content we are looking for

IE:

 Assertion with == failed
 code:  assert html_response(conn, 302) == "Password Reset Sent to #{user.email()}"
 left:  "<html><body>You are being <a href=\"/login\">redirected</a>.</body></html>"
 right: "Password Reset Sent to email-11@example.com"

So my question is, how do I perform the redirect so that I can see the state after the redirection has occurred?


#2

Something like this should work:

conn = post conn, user_path(conn, :create_pass_reset, %{"user" => %{"email" => user.email}})
assert "/login" = redir_path = redirected_to(conn, 302)
conn = get(recycle(conn), redir_path)
assert html_response(conn, 302) ==  "Password Reset Sent to #{user.email}"

#3

Gonna have to use that assert / assignment again, assert "/login" = redir_path = redirected_to(conn, 302) :tada:
Thank you yet again @chrismccord


#4

Also what are your thoughts about this pattern of following the redirect?
This is something I’ve yet to see in the community.


#5

It’s just fine pattern wise. It’s not exactly the same, but our context generators make use of redirected_params to construct a path and then get the show page of a created resource:


#6

Sorry to bug you again on this. I’m struggling with something when maintaining state.

I get the principle of saving conn.assigns to save authentication to reuse with different calls. I’m probably misunderstanding, but how do I make sure the validation errors don’t get tossed. Or the 302 is follow without recycling (I think this would solve it)?

The below is the code in question, there is a setup [:create_user] for the describe block.

@tag :authenticated
test "renders errors when data is invalid", %{conn: conn, client: client} do
  conn = put(conn, client_path(conn, :update, client), client: @invalid_attrs)
  assert html_response(conn, 200) =~ "Edit Client"
end

This gets a 302 and “you are being redirected”.