I have a very simple web application that currently only supports users registering/logging in and out etc.
I have followed the procedure from the Chris McCord book on how to do this.
I want to write unit tests to make my app future proof and all the other goodness tests provide.
I have written my controller in such a way that only a logged in user can edit his own profile. If the user is trying to edit a profile from another user the user is redirected to the homepage.
In my unit test I want to assign a user to the connection, and if that user’s id matches the id of the user that’s going to be edited, I allow it.
I observe that in my controller the assigns of the connection are always empty. So my question is, how can I assign the current user to my connection for this test?
I have added the relevant code below, and the entire repo is online available here: https://gitlab.call-cc.be/petprojects/gym/tree/user_front_test
Test
defp create_user(_) do
user = fixture(:user)
{:ok, user: user}
end
def fixture(:user) do
{:ok, user} = Gymbook.Domain.create_user(@valid_attrs)
user
end
describe "edit user" do
setup [:create_user]
@tag :logged_in
test "can edit own profile", %{conn: conn, user: user} do
# Add user to connection.
conn = Plug.Conn.assign(conn, :current_user, user)
conn = get(conn, user_path(conn, :edit, user))
assert html_response(conn, 200) =~ "Edit User"
end
end
UserController
def edit(conn, %{"id" => id}) do
if current_user_id?(conn, id) do
user = Domain.get_user!(id)
changeset = Domain.change_user(user)
render(conn, "edit.html", user: user, changeset: changeset)
else
handle_not_allowed(conn)
end
end
defp current_user_id?(conn, id) do
current_user = conn.assigns[:current_user]
not (current_user == nil or "#{current_user.id}" != id)
end
defp handle_not_allowed(conn) do
conn
|> put_flash(:info, "Not allowed to do that. Sorry.")
|> redirect(to: page_path(conn, :index))
end
Gymbook.WebsiteWeb.Auth
defmodule Gymbook.WebsiteWeb.Auth do
import Plug.Conn
import Comeonin.Bcrypt, only: [checkpw: 2, dummy_checkpw: 0]
def init(opts) do
Keyword.fetch!(opts, :repo)
end
def call(conn, repo) do
user_id = get_session(conn, :user_id)
user = user_id && repo.get(Gymbook.Domain.User, user_id)
assign(conn, :current_user, user)
end
def login(conn, user) do
conn
|> assign(:current_user, user)
|> put_session(:user_id, user.id)
|> configure_session(renew: true)
end
def logout(conn) do
configure_session(conn, drop: true)
end
def login_by_username_and_pass(conn, username, given_pass, opts) do
repo = Keyword.fetch!(opts, :repo)
user = repo.get_by(Gymbook.Domain.User, username: username)
cond do
user && checkpw(given_pass, user.password_hash) ->
{:ok, login(conn, user)}
user ->
{:error, :unauthorized, conn}
true ->
dummy_checkpw()
{:error, :not_found, conn}
end
end
end