2.1 KiB · text History dc2edab
defmodule DiogramosWeb.MagicLinkControllerTest do
  use DiogramosWeb.ConnCase, async: true

  import Diogramos.AccountsFixtures

  alias Diogramos.Accounts

  test "hands a browser off to the web login flow", %{conn: conn} do
    conn = get(conn, ~p"/m/some-token")

    assert redirected_to(conn) == ~p"/users/log-in/some-token"
  end

  test "the emailed link points at /m/ so Android can claim it", %{conn: conn} do
    user = user_fixture()
    # user_fixture/0 logs the user in, which sends its own email first.
    assert_receive {:email, _registration}

    post(conn, ~p"/api/v1/sessions/request_magic_link", %{email: user.email})

    assert_receive {:email, email}
    assert email.text_body =~ "/m/"
    refute email.text_body =~ "/users/log-in/"
  end

  test "an unknown address still answers 204, so the endpoint cannot enumerate accounts", %{
    conn: conn
  } do
    conn = post(conn, ~p"/api/v1/sessions/request_magic_link", %{email: "nobody@example.com"})

    assert response(conn, 204)
  end

  test "redeeming a magic-link token yields a working api token", %{conn: conn} do
    user = user_fixture()
    {token, _} = generate_user_magic_link_token(user)

    conn = post(conn, ~p"/api/v1/sessions/redeem", %{token: token, label: "Pixel 7"})

    assert %{"token" => api_token, "user" => %{"email" => email}} = json_response(conn, 201)
    assert email == user.email
    assert {fetched, _id} = Accounts.fetch_user_by_api_token(api_token)
    assert fetched.id == user.id
    assert [%{label: "Pixel 7"}] = Accounts.list_api_tokens(user)
  end

  test "a magic-link token is single use", %{conn: conn} do
    user = user_fixture()
    {token, _} = generate_user_magic_link_token(user)

    assert json_response(post(conn, ~p"/api/v1/sessions/redeem", %{token: token}), 201)

    conn = post(build_conn(), ~p"/api/v1/sessions/redeem", %{token: token})
    assert %{"error" => %{"code" => "unauthenticated"}} = json_response(conn, 401)
  end

  test "rejects a garbage token", %{conn: conn} do
    conn = post(conn, ~p"/api/v1/sessions/redeem", %{token: "nope"})

    assert %{"error" => %{"code" => "unauthenticated"}} = json_response(conn, 401)
  end
end