-
-
Notifications
You must be signed in to change notification settings - Fork 158
Description
Hi I really appreciate your work on Pow Auth. It is really great and compact. For learning purposes I try to create my custom controllers for the most important cases. Just to know how it works under the hood, to test it easily in Postman (putting tokens in json and pasting them in another bodies) and how to write good tests in Elixir.
I've struggling for many hours with testing reset password controller, it raises errors every time and that forced me to write an issue cause my digging through web leads to nowhere :)
I start from beginning. Here is my forgot_password func. Pretty straight forward except token in json - easy to test with postman.
@spec forgot_password(Conn.t(), map()) :: Conn.t()
def forgot_password(conn, email) do
conn
|> PowResetPassword.Plug.create_reset_token(email)
|> case do
{:ok, %{token: token, user: _user}, conn} ->
#send email to be implemented
conn
|> put_status(200)
|> json(%{data: %{status: 200, message: "Email has been sent", token: token}})
{:error, _changeset, conn} ->
conn
|> put_status(200)
|> json(%{data: %{status: 200, message: "Email has been sent"}})
end
end
And here is my reset_password controller:
@spec reset_password(Conn.t(), map()) :: Conn.t()
def reset_password(conn, %{"id" => token, "user" => user_params}) do
with {:ok, conn} <- PowResetPassword.Plug.load_user_by_token(conn, token),
{:ok, _user, conn} <- PowResetPassword.Plug.update_user_password(conn, user_params) do
json(conn, %{status: "Password changed"})
else
{:error, _changeset, conn} ->
json(conn, %{error: %{message: "Passwords are not the same"}})
_ ->
json(conn, %{error: %{message: "Expired Token"}})
end
end
Everything works fine during testing in Postman - I dont know yet how to use session/cache token in this application so I use what I learnt while learning C# with JWT tokes.
I put my forgot_password and reset_password tests in one file (the same like they both are in one controller file) Here is my forgot_password part:
setup do
user =
%User{}
|> User.changeset(%{email: "[email protected]", password: @password, password_confirmation: @password})
|> Repo.insert!()
{:ok, user: user}
end
describe "forgot_password/2" do
test "with email in database", %{conn: conn} do
conn = post(conn, Routes.password_path(conn, :forgot_password, @valid_email))
assert json = json_response(conn, 200)
assert json["data"]["status"]
assert json["data"]["message"]
assert json["data"]["token"]
end
test "with invalid email", %{conn: conn} do
conn = post(conn, Routes.password_path(conn, :forgot_password, @invalid_email))
assert json = json_response(conn, 200)
assert json["data"]["status"]
assert json["data"]["message"]
end
end
It works well. Simple, compact, 5 minutes of work. Then problems started to appear - I've tried many configurations of reset password tests but nothing seems to work.
1st attemp:
@valid_params %{"id" => "token", "user" => %{"password" => @new_password, "password_confirmation" => @new_password}}
describe "reset_password/2" do
test "with valid token and passwords", %{conn: conn} do
conn = post(conn, Routes.password_path(conn, :reset_password, @valid_params))
assert json = json_response(conn, 200)
assert json["status"]
end
end
Witth error:
Expected truthy, got nil
code: assert json["status"]
arguments:
# 1
%{"error" => %{"message" => "Expired Token"}}
# 2
"status"
I suppose it needs real token. So pretty simple that It crashed.
2nd attemp:
use PowApiTemplateWeb.ConnCase
alias Plug.Conn
alias PowApiTemplate.{Repo, Users.User}
alias PowResetPassword.Plug
alias Pow.Plug, as: PowPlug
setup do
user =
%User{}
|> User.changeset(%{email: "[email protected]", password: @password, password_confirmation: @password})
|> Repo.insert!()
{:ok, user: user}
end
describe "reset_password/2" do
setup %{conn: conn} do
token = PowResetPassword.Plug.create_reset_token(conn, "[email protected]")
{:ok, conn: conn, token: token}
end
test "with valid token and passwords", %{conn: conn} do
conn = post(conn, Routes.password_path(conn, :reset_password, %{"id" => token, "user" => %{"password" => @new_password, "password_confirmation" => @new_password}}))
assert json = json_response(conn, 200)
assert json["status"]
end
end
At first I thought it has to be working. Token is invoked and I didnt use any variables to omit mistakes. Then I got error:
(Pow.Config.ConfigError) Pow configuration not found in connection. Please use a Pow plug that puts the Pow configuration in the plug connection.
I have no idea what to do now. I spent many hours on elixir forum, with documentation and on github trying to find people with similar problem or repos with custom controllers but it leads to nowhere. I have in my head another solutions, but I know too little yet to do it all by myself without any tips. I dont want to go further without understanding this part and I want to have my own boilerplate for my projects.
I have also some questions:
- What comes to my mind is that maybe I need to mock some part of test. Dont know yet which.
- I dont know If that type of controllers are possible/secure to go in production. I know that whole Pow is about caching tokes and invoking next functions then. If I use them like I did - they are needed to be pasted into params by "hand" - are they still also passed under the hood in cache? For now I learn mostly API/Backend stuff and it's easy to test it in Postman in contrast to playing with cache/session tokes, but If it is terrible way I just need to know and learn it in other way (this is how 99% courses for C# are taught).
Greetings and thanks for your help :)