# `PhoenixKit.Test.Fixtures`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.13.7/lib/phoenix_kit/test/fixtures.ex#L1)

Test fixtures and session helpers for host applications.

> #### ExUnit only {: .warning}
>
> 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

# `admin_fixture`

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

A confirmed user holding the Admin role.

# `confirmed_user_fixture`

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

A registered user whose email is confirmed.

# `log_in_user`

```elixir
@spec log_in_user(Plug.Conn.t(), PhoenixKit.Users.Auth.User.t()) :: Plug.Conn.t()
```

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`

```elixir
@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`

```elixir
@spec scope_for(PhoenixKit.Users.Auth.User.t() | nil) ::
  PhoenixKit.Users.Auth.Scope.t()
```

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

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

# `unique_user_email`

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

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

# `user_fixture`

```elixir
@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`

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

A password that satisfies the registration changeset.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
