ravernkoh
Wallaby testing when browser session is required (i.e. login)
How do I test some code if a browser session with some user data inside (perhaps from Guardian) is required? How do I get that session data into my Wallaby session?
Most Liked
thomasbrus
For future reference in case anyone bumps into this:
# test/support/test_helpers.ex
defmodule MyAppWeb.TestHelpers do
@user_remember_me "_my_app_web_user_remember_me"
def log_in(%{session: session} = context) do
user = Map.get(context, :user, user_fixture())
user_token = MyApp.Accounts.generate_user_session_token(user)
endpoint_opts = Application.get_env(:dorado, MyAppWeb.Endpoint)
secret_key_base = Keyword.fetch!(endpoint_opts, :secret_key_base)
conn =
%Plug.Conn{secret_key_base: secret_key_base}
|> Plug.Conn.put_resp_cookie(@user_remember_me, user_token, sign: true)
session
|> visit("/")
|> set_cookie(@user_remember_me, conn.resp_cookies[@user_remember_me][:value])
{:ok, %{session: session, user: user}}
end
end
This assumes you created MyApp.Accounts via mix phx.gen.auth. The test setup can then simply look like this:
setup context do
log_in(context)
end
hubertlepicki
I see this discussion reanimated and maybe just 2 cents from me. I usually solve this with having “autologin” controller, and corresponding route that are only present if Mix.env() == :test.
Then, I just do “visit /autologin/:user_id” as a first step of the test and user is logged in to the account specified by ID.
Again, this needs to be deployed carefully so that the route nor controller are not present in other environments, but should work well with Playwright and Wallaby alike.
NobbZ
Yes. That’s what setup is for. Or you can write a helper function that does this.
hubertlepicki
In your router:
if Mix.env() == :test do
scope "/autologin", Web do
pipe_through(:browser)
get("/:account_id", AutologinTestController, :autologin)
end
end
And then in your test/support/autologin_test_controller.ex:
defmodule Web.AutologinTestController do
@moduledoc "This controller is used for tests only and is compiled
in MIX_ENV=test environment only. It allows to log in to accounts by
visiting /autologin/:account_id, working around Oauth2/Google login."
use Web, :controller
def autologin(conn, %{"account_id" => account_id}) do
account = DB.Repo.get!(DB.Account, account_id)
Web.LogIn.login(conn, account)
end
end
Adjust for your code structure, but that’s roughly it. A few lines.
Remember to wrap the route in the if clause and then also put the controller in test/support rather than usual location so it doesn’t get compiled in other environments.
The Web.Login.login/2 is the same function that’s used by actual controllers so you are sure it’s setting all the session variables the same way as production code.
LostKobrakai
If you’re not concerned about phoenix’s ability to hold the session you can also test this without browser testing. You should also be able to set values to the conn’s session manually like so:
conn =
conn
|> bypass_through(MyAppWeb.Router, [:browser])
|> put_session(:account_id, 1)
get conn, …







