pow icon indicating copy to clipboard operation
pow copied to clipboard

Passing POW session information to a LiveView in test?

Open molenick opened this issue 4 years ago • 3 comments
trafficstars

Thanks for the great library! :)

I'm trying to pass an authenticated user to a LiveView so I can access current_user, with the end goal to authorize access to resources based on user. I've read a few of the (very helpful and detailed) issues on integrating Pow and LiveViews, and am able to get access to the user inside of the LiveView during mount by verifying their auth key from the session.

My issues arises when I try to replicate this behavior in test. I want to be able to simulate a log so that I can test authenticated and unauthenticated behaviors, but I've been struggling a bit to get this piece in place. In regular controllers, I've done this with a test callback:

  defp authenticate_user(%{conn: conn, user: user}) do
    auth_conn = Pow.Plug.assign_current_user(conn, user, otp_app: :euchre)

    %{auth_conn: auth_conn}
  end

I tried doing this in my LiveView tests but am having a bit of trouble. I noticed that during my test runs that session was always nil in my LiveView's mount. I did some searching and it seems like that's pretty normal for LiveView tests, and that it seemed like most people solved it by either piggybacking off another request where there is already a session, or injecting session data through test callbacks. I've been trying the "inject session data" approach.

How can I derive a user's auth key from their Pow user struct? My secondary question is: does this seem like a good approach for my goals, or is there a better way to go about passing a user to a LiveView and testing it? Thanks!

molenick avatar Mar 04 '21 01:03 molenick

I just got done with this. I added this function to my setup macro:

defp setup_session(%{ conn: conn }) do
    conn = Plug.Test.init_test_session(conn, %{})
    opts = Pow.Plug.Session.init(otp_app: :userdocs_web)
    conn =
      conn
      |> Plug.Test.init_test_session(%{})
      |> Pow.Plug.Session.call(opts)
      |> Pow.Plug.Session.do_create(first_user(), opts)
    :timer.sleep(100)
    %{ conn: conn }
  end

I think the only thing that isn't covered by plug or pow is this function that gets the first user I created in my fixtures:

defp first_user(), do: Users.list_users() |> Enum.at(0)

Now I'm looking, that first conn = Plug.Test.init ... is not necessary, it's in the pipeline. You could also be smarter about the first_user() call and just get it from the args for the fixture.

If you dig around, you'll find this solution prosed previously in this repo.

I don't know how to access the auth key, but this covers getting the user logged in and the session created.

johns10 avatar Mar 31 '21 17:03 johns10

Using @johns10's example above I documented my full auth/test helper setup for Pow with LiveViews. See it here.

I am piecing together various things I've found so it'd be worth consulting threads like this to ensure this follows best security practices before including in your app.

kieraneglin avatar Aug 17 '21 16:08 kieraneglin

I'll have to check out your solution because I'm still having a hard time with my tests.

johns10 avatar Aug 23 '21 01:08 johns10