defmodule ToweropsWeb.UserConfirmationControllerTest do use ToweropsWeb.ConnCase, async: true import Towerops.AccountsFixtures alias Towerops.Accounts describe "GET /users/confirm" do test "renders the confirmation instructions page", %{conn: conn} do conn = get(conn, ~p"/users/confirm") response = html_response(conn, 200) assert response =~ "confirm" end end describe "POST /users/confirm" do test "sends confirmation email for unconfirmed user", %{conn: conn} do user = unconfirmed_user_fixture() conn = post(conn, ~p"/users/confirm", %{"user" => %{"email" => user.email}}) assert redirected_to(conn) == ~p"/users/log-in" assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "If your email is in our system" end test "does not reveal if email exists (non-existent email)", %{conn: conn} do conn = post(conn, ~p"/users/confirm", %{"user" => %{"email" => "nobody@example.com"}}) assert redirected_to(conn) == ~p"/users/log-in" assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "If your email is in our system" end test "does not send email for already confirmed user", %{conn: conn} do user = user_fixture() # user_fixture auto-confirms, so this should not send an email conn = post(conn, ~p"/users/confirm", %{"user" => %{"email" => user.email}}) # Should still show the generic success message (no email enumeration) assert redirected_to(conn) == ~p"/users/log-in" assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "If your email is in our system" end end describe "GET /users/confirm/:token" do test "confirms user with valid token", %{conn: conn} do user = unconfirmed_user_fixture() token = extract_user_token(fn url -> Accounts.deliver_user_confirmation_instructions(user, url) end) conn = get(conn, ~p"/users/confirm/#{token}") assert redirected_to(conn) == ~p"/users/log-in" assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "confirmed" end test "rejects invalid token", %{conn: conn} do conn = get(conn, ~p"/users/confirm/invalid-token-value") assert redirected_to(conn) == ~p"/users/log-in" assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "invalid or has expired" end test "rejects already-used token", %{conn: conn} do user = unconfirmed_user_fixture() token = extract_user_token(fn url -> Accounts.deliver_user_confirmation_instructions(user, url) end) # Use the token once assert {:ok, _} = Accounts.confirm_user(token) # Try to use again conn = get(conn, ~p"/users/confirm/#{token}") assert redirected_to(conn) == ~p"/users/log-in" assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "invalid or has expired" end end end