caslu
Testing pow authenticated controllers
I added Pow to my application using this guide because i have a JSON api structure, but after integrate with pow, my controller tests broke because neither of them needed to have a session before and now they do. The problem is that i’m not being able to make the tests work, my approach so far was change the default setup method generated by phoenix to this:
# before
setup %{conn: conn} do
{:ok, conn: put_req_header(conn, "accept", "application/json")}
end
# now
setup %{conn: conn} do
user = user_fixture()
authed_conn =
conn
|> put_req_header("accept", "application/json")
|> pow.plug.assign_current_user(user, [])
{:ok, conn: authed_conn}
end
Now the index test pass successfully, but the others give me this error message:
** (RuntimeError) expected connection to have a response but no response was set/sent.
Please verify that you assign to "conn" after a request:
conn = get(conn, "/")
assert html_response(conn) =~ "Hello"
code: assert json_response(conn, 422)["errors"] != %{}
stacktrace:
(phoenix 1.7.12) lib/phoenix/test/conn_test.ex:358: Phoenix.ConnTest.response/2
(phoenix 1.7.12) lib/phoenix/test/conn_test.ex:419: Phoenix.ConnTest.json_response/2
test/ponto_cao_web/controllers/pet_controller_test.exs:106: (test)
I didn’t find in pow docs and repo some recommended way to tests authenticated controllers on API only projects, can you guys help me to understand why this is happening ?
Marked As Solved
LostKobrakai
A conn knows and stores if it was already used to make a request (iirc conn.state). So your two approaches are.
# conn was used before
conn =
conn
# assign current user to the used conn
|> Pow.Plug.assign_current_user(user, [])
# get/2 detects the conn as already being used and recycles it,
# which doesn't retain the assign you added
|> get(~p"/api/events/#{id}")
and
# conn was used before
conn =
build_conn()
# assign current user to the used conn
|> Pow.Plug.assign_current_user(user, [])
# get/2 detects the conn as not used yet, so no recycling is happening
# the assign stays
|> get(~p"/api/events/#{id}")
You could do conn |> recycle() |> Pow.Plug.assign_current_user(user, []) to work around the automatic recycling happing at an inconvencient time.
You could also consider not writing to conn.assigns, but to put the authentication details in the session. That way authentication will persist across recycles just like it does persist across many requests outside of testing.
Also Liked
LostKobrakai
Recycling a conn tries to do essentially the same as what happens when a browser would navigate to a new route. Only things like cookies, some headers, hostname, … will be retained. assigns are not retained between multiple requests being made, but need to be computed and set freshly for each request, so the same applies with recycles.
Here you have a conn, which was already used to do a request, then you assign some data and then you request a new page, trigger a recycle and therefore get rid of tje assign again.
If you do multiple request you likely want to authenticate, so that a session is started and not just for a single request by setting just assigns.
Hermanverschooten
Haven’t used pow myself, but I guess you should do something like they do in their tests,
conn |> PowPlug.assign_current_user(@user, [])
Hermanverschooten
Last Post!
habutre
I was facing the same issue and what worked for me instead of recycling the conn was to take advantage of immutability and not reuse the authenticated connection from setup
I named the conn from context as conn_auth, use it in my calls e.g. conn = get(conn_auth,…)
So my authenticated connection was kept untouched and I could assert my responses normally and as much as I need
Popular in Questions
Other popular topics
Latest Phoenix Threads
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #hex
- #security









