Testing session creation in login controller

I’m trying to add a very simplistic login page to my Phoenix application based on the contexts guide, so I can start adding the concept of user ownership to my resources. My login form seems to work interactively, but in my unit tests, it seems to be stuck in a redirection loop. I suspect this is because, unlike in the other controllers, a session is being created. I’m not sure how to handle this. I can find plenty of articles and threads on creating a session for tests, but not testing the thing that actually creates sessions in the application.

Can anyone offer any insight?

Test output below, and test source here

  1) test sign in redirects to login page and shows error when credential is invalid (PaddyWeb.SessionControllerTest)
     test/paddy_web/controllers/session_controller_test.exs:30
     ** (RuntimeError) expected response with status 200, got: 302, with body:
     <html><body>You are being <a href="/sessions/new">redirected</a>.</body></html>
     code: assert html_response(conn, 200) =~ "Bad email/password combination"
     stacktrace:
       (phoenix 1.4.10) lib/phoenix/test/conn_test.ex:373: Phoenix.ConnTest.response/2
       (phoenix 1.4.10) lib/phoenix/test/conn_test.ex:387: Phoenix.ConnTest.html_response/2
       test/paddy_web/controllers/session_controller_test.exs:37: (test)



  2) test sign in creates session and redirects to / when credential is valid (PaddyWeb.SessionControllerTest)
     test/paddy_web/controllers/session_controller_test.exs:22
     Assertion with == failed
     code:  assert redirected_to(conn) == Routes.page_path(conn, :index)
     left:  "/sessions/new"
     right: "/"
     stacktrace:
       test/paddy_web/controllers/session_controller_test.exs:25: (test)

The link is private, so I can’t see the source.

1) test sign in redirects to login page and shows error when credential is invalid (PaddyWeb.SessionControllerTest)
** (RuntimeError) expected response with status 200, got: 302

This can be either that your auth is letting people in with bad credentials or there is some plug that’s doing a redirect even when it shouldn’t.

1 Like

Oops! Sorry, I messed up the project settings. It should be viewable now.

In the test, you never actually create the user in the database, so the controller rightfully redirects you. On a side note, when the authentication fails, I think you can just re-render the “new.html” template.

1 Like

Oops. Yeah, that certainly won’t help. I seem to be making progress, but it seems to be stuck in a redirect loop, because even though I assert redirected_to(conn), the subsequent assert html_response(conn, 200) fails because the response code is 301.

  1) test sign in creates session and redirects to / when credential is valid (PaddyWeb.SessionControllerTest)
     test/paddy_web/controllers/session_controller_test.exs:25
     ** (RuntimeError) expected response with status 200, got: 302, with body:
     <html><body>You are being <a href="/">redirected</a>.</body></html>
     code: assert html_response(conn, 200) =~ "Welcome back!"
     stacktrace:
       (phoenix 1.4.10) lib/phoenix/test/conn_test.ex:373: Phoenix.ConnTest.response/2
       (phoenix 1.4.10) lib/phoenix/test/conn_test.ex:387: Phoenix.ConnTest.html_response/2
       test/paddy_web/controllers/session_controller_test.exs:30: (test)



  2) test sign in redirects to login page and shows error when credential is invalid (PaddyWeb.SessionControllerTest)
     test/paddy_web/controllers/session_controller_test.exs:33
     ** (RuntimeError) expected response with status 200, got: 302, with body:
     <html><body>You are being <a href="/sessions/new">redirected</a>.</body></html>
     code: assert html_response(conn, 200) =~ "Bad email/password combination"
     stacktrace:
       (phoenix 1.4.10) lib/phoenix/test/conn_test.ex:373: Phoenix.ConnTest.response/2
       (phoenix 1.4.10) lib/phoenix/test/conn_test.ex:387: Phoenix.ConnTest.html_response/2
       test/paddy_web/controllers/session_controller_test.exs:38: (test)
assert redirected_to(conn) == Routes.page_path(conn, :index)

assert html_response(conn, 200) =~ "Welcome back!"

This code doesn’t modify the conn, so you’re not in a redirect loop, it’s just the same conn with the same status. You need to make another request, just like the browser would do:

assert redirected_to(conn) == Routes.page_path(conn, :index)

# Use the same conn to keep the session.
conn = get(conn, Routes.page_path(conn, :index))

assert html_response(conn, 200) =~ "Welcome back!"

This should hopefully work.

Also have a look at phx.gen.auth - it generates a fully fledged auth for a Phoenix app with a really nice test suite.

1 Like

Thanks, that fixed it!

This authentication system is just a stub so I can implement parts of my application that require the concept of user sessions, but I was not aware of phx.gen.auth, only guardian and comeonin, the two mentioned in the Phoenix Contexts guide.