diff --git a/lib/perseus/auth.ex b/lib/perseus/auth.ex index 55a9b85..75de505 100644 --- a/lib/perseus/auth.ex +++ b/lib/perseus/auth.ex @@ -9,12 +9,17 @@ defmodule Perseus.Auth do @signup_token_ttl 60 * 15 @session_token_ttl 60 * 60 - def send_login_email(email, url_fun) do + def send_login_email(email, url_fun \\ nil) do with {:ok, _} <- Accounts.get_user_by_email(email), {:ok, token} <- generate_login_token(email), - encoded_token <- BinaryUtils.encode(token), - {:ok, _} <- UserNotifier.deliver_login_link(email, url_fun.(encoded_token)) do - :ok + encoded_token <- BinaryUtils.encode(token) do + # If `url_fun` is provided, deliver the login link via email + if url_fun do + UserNotifier.deliver_login_link(email, url_fun.(encoded_token)) + else + # Otherwise, just return the encoded token + {:ok, encoded_token} + end else _ -> :error end diff --git a/test/perseus/auth/token_store_test.exs b/test/perseus/auth/token_store_test.exs index cd9d584..ca0f0cb 100644 --- a/test/perseus/auth/token_store_test.exs +++ b/test/perseus/auth/token_store_test.exs @@ -13,6 +13,7 @@ defmodule Perseus.Auth.TokenStoreTest do setup do # Create an ETS table for testing purposes init_table(@magic_link_table) + init_table(@signup_table) init_table(@session_table) :ok end @@ -56,9 +57,9 @@ defmodule Perseus.Auth.TokenStoreTest do end test "stores session token correctly", %{token: token, user: user, ttl: ttl} do - TokenStore.store_signup_token(token, user, ttl) + TokenStore.store_session_token(token, user, ttl) - assert [{^token, ^user, _}] = :ets.lookup(@signup_table, token) + assert [{^token, ^user, _}] = :ets.lookup(@session_table, token) end end diff --git a/test/perseus_web/resolvers/auth_test.exs b/test/perseus_web/resolvers/auth_test.exs new file mode 100644 index 0000000..3984ee7 --- /dev/null +++ b/test/perseus_web/resolvers/auth_test.exs @@ -0,0 +1,55 @@ +defmodule PerseusWeb.Resolvers.AuthTest do + use Perseus.DataCase + + alias Perseus.Auth + alias PerseusWeb.Resolvers + + import Perseus.AccountsFixtures + + describe "login_user/3" do + setup do + %{user: user_fixture()} + end + + test "with valid context should login user", %{user: user} do + result = Resolvers.Auth.login_user(nil, nil, %{context: %{email: user.email}}) + + # Assert that the resolver returns :ok and a session_token + assert {:ok, %{session_token: session_token}} = result + assert {:ok, ^user} = Auth.find_user(session_token) + end + + test "with invalid email address should return error" do + result = Resolvers.Auth.login_user(nil, nil, %{context: %{email: "invalid@example.com"}}) + + # Assert that the resolver returns :ok and a session_token + assert {:error, "User not found"} = result + end + end + + describe "signup_user/3" do + setup do + %{user: valid_user_attributes()} + end + + test "with valid data should signup user", %{user: user} do + result = Resolvers.Auth.signup_user(nil, %{user: user}, %{context: %{email: user.email}}) + + assert {:ok, %{session: _, new_user: created_user}} = result + assert created_user.email == user.email + assert created_user.first_name == user.first_name + assert created_user.last_name == user.last_name + assert created_user.verified == false + end + + test "with invalid data should return a changeset" do + result = + Resolvers.Auth.signup_user(nil, %{user: %{first_name: "test"}}, %{ + context: %{email: "invalid"} + }) + + assert {:error, %Ecto.Changeset{} = changeset} = result + assert "can't be blank" in errors_on(changeset).last_name + end + end +end diff --git a/test/perseus_web/schema/mutations/auth_mutations_test.exs b/test/perseus_web/schema/mutations/auth_mutations_test.exs new file mode 100644 index 0000000..908d193 --- /dev/null +++ b/test/perseus_web/schema/mutations/auth_mutations_test.exs @@ -0,0 +1,44 @@ +defmodule PerseusWeb.Schema.Mutations.AuthMutationsTest do + alias Perseus.Utils.BinaryUtils + alias Perseus.Auth + use PerseusWeb.ConnCase, async: true + + import Perseus.AccountsFixtures + + # Define the query that you will be testing + @login_query """ + mutation startSession { + logIn { + sessionToken + } + } + """ + + describe "login mutation" do + setup do + user = user_fixture() + {:ok, token} = Auth.send_login_email(user.email) + %{user: user, token: token} + end + + test "should login when email is found", %{conn: conn, user: user, token: token} do + conn = + conn + |> put_req_header("authorization", "MagicLink " <> token) + |> put_req_header("x-custom-header", "custom-value") + |> post("/api/graphql", %{query: @login_query}) + + assert json_response(conn, 200) + response_data = json_response(conn, 200)["data"] + + assert %{ + "logIn" => %{ + "sessionToken" => session_token + } + } = response_data + + {:ok, decoded_session_token} = BinaryUtils.decode(session_token) + assert {:ok, ^user} = Auth.find_user(decoded_session_token) + end + end +end diff --git a/test/support/fixtures/accounts_fixtures.ex b/test/support/fixtures/accounts_fixtures.ex index 5055b63..e99825a 100644 --- a/test/support/fixtures/accounts_fixtures.ex +++ b/test/support/fixtures/accounts_fixtures.ex @@ -10,14 +10,18 @@ defmodule Perseus.AccountsFixtures do def user_fixture(attrs \\ %{}) do {:ok, user} = attrs - |> Enum.into(%{ - email: "someemail@example.com", - first_name: "some first_name", - last_name: "some last_name", - verified: true - }) + |> valid_user_attributes() |> Perseus.Accounts.create_user() user end + + def valid_user_attributes(attr \\ %{}) do + Enum.into(attr, %{ + email: "someemail@example.com", + first_name: "some first_name", + last_name: "some last_name", + verified: true + }) + end end