PhoenixKit.Test.Fixtures (phoenix_kit v2.7.0)

Copy Markdown View Source

Test fixtures and session helpers for host applications.

ExUnit only

These compile into your production build because they live in lib/, but they exist solely for tests and are not part of the runtime API. Nothing here is a supported thing to call from application code.

Why this ships

Every host was writing the same four helpers, and the hand-rolled login was subtly wrong: it set :user_token but not :live_socket_id, so LiveView's disconnect-on-logout never fired and a session-invalidation test was the only thing that would ever have caught it. That is a worse outcome than duplication, and it is what a shipped helper fixes.

What is deliberately NOT here

No ConnCase, no DataCase, no Ecto.Adapters.SQL.Sandbox calls. Those are bound to your endpoint and your repo, and a copy compiled in the kit's context could not adapt to either. Sandbox ownership stays yours. Everything here is portable: the fixtures go through Auth.register_user/1, which uses the configured repo, and the session helpers only put keys into a conn.

Confirmed vs unconfirmed — read the test, do not memorise a default

user_fixture/1 produces an unconfirmed user, honestly mirroring what register_user/1 does. Confirmation flips authentication behaviour, so a fixture that silently confirmed would leave a reader of

user = user_fixture()

unable to tell why a redirect gate did or did not fire. Ask for confirmed_user_fixture/1 when you mean confirmed.

(confirmed_at == nil after registration is correct, not a defect being papered over: registration_changeset/3 refuses to cast it, confirmation is its own transition, and the gate exists precisely to handle the registered-but-unconfirmed state — so tests have to be able to produce it.)

Usage

defmodule MyAppWeb.AdminTest do
  use MyAppWeb.ConnCase
  import PhoenixKit.Test.Fixtures

  test "an admin reaches the dashboard", %{conn: conn} do
    %{conn: conn} = register_and_log_in_user(%{conn: conn})
    assert conn |> get(~p"/phoenix_kit/admin") |> html_response(200)
  end
end

Summary

Functions

A confirmed user holding the Admin role.

A registered user whose email is confirmed.

Puts user's session token into conn.

A confirmed user, logged in on the given conn. The 90% case.

A real %Scope{} for user, with roles and permissions loaded.

An email address no other fixture in this run will use.

A registered, unconfirmed user.

A password that satisfies the registration changeset.

Functions

admin_fixture(attrs \\ %{})

@spec admin_fixture(map()) :: PhoenixKit.Users.Auth.User.t()

A confirmed user holding the Admin role.

confirmed_user_fixture(attrs \\ %{})

@spec confirmed_user_fixture(map()) :: PhoenixKit.Users.Auth.User.t()

A registered user whose email is confirmed.

log_in_user(conn, user)

Puts user's session token into conn.

Sets both :user_token and :live_socket_id. The second one is the reason this helper exists: without it PhoenixKitWeb.Endpoint.broadcast has no topic to reach the socket on, so logging out never disconnects the LiveView — and nothing but a session-invalidation test would reveal it.

register_and_log_in_user(context)

@spec register_and_log_in_user(map()) :: map()

A confirmed user, logged in on the given conn. The 90% case.

Returns the context map with :user and an updated :conn, so it composes as an ExUnit setup:

setup :register_and_log_in_user

scope_for(user)

A real %Scope{} for user, with roles and permissions loaded.

For testing something that takes a scope directly, without a conn.

unique_user_email()

@spec unique_user_email() :: String.t()

An email address no other fixture in this run will use.

user_fixture(attrs \\ %{})

@spec user_fixture(map()) :: PhoenixKit.Users.Auth.User.t()

A registered, unconfirmed user.

Pass any register_user/1 attributes to override; email and password are filled in with unique valid values when omitted.

valid_user_password()

@spec valid_user_password() :: String.t()

A password that satisfies the registration changeset.