Skip to content

Reset password - test fails issue #679

@mateuszbabski

Description

@mateuszbabski

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:

  1. What comes to my mind is that maybe I need to mock some part of test. Dont know yet which.
  2. 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 :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions