prop/test/microwaveprop_web/live/beacon_live_test.exs
Graham McIntire ddec874c38 Add /beacons CRUD and /users admin page
Beacons:
- Scaffolded with phx.gen.live then reworked so reads are public
  and mutations go through a live_session gated by the new
  :require_admin on_mount hook in UserAuth
- Beacon schema stores frequency (MHz), callsign, grid, lat/lon,
  power (W), and height above ground (m); grid auto-derives from
  lat/lon when left blank via Maidenhead.from_latlon
- Adds Maidenhead.from_latlon/3 so we can compute grids locally
  instead of hitting an external API

Users admin page:
- /users and /users/:id/edit (admin-only) for listing, editing
  (callsign/name/email/is_admin), and deleting other users
- Adds Accounts.list_users, admin_update_user, delete_user, and
  a dedicated admin_changeset on the User schema
- Nav gains a "Users" link for admins and a "Beacons" link for
  everyone
2026-04-08 12:01:34 -05:00

94 lines
2.8 KiB
Elixir

defmodule MicrowavepropWeb.BeaconLiveTest do
use MicrowavepropWeb.ConnCase
import Microwaveprop.AccountsFixtures
import Microwaveprop.BeaconsFixtures
import Phoenix.LiveViewTest
alias Microwaveprop.Accounts
defp promote_to_admin(user) do
{:ok, user} = Accounts.admin_update_user(user, %{is_admin: true})
user
end
defp admin_user_fixture do
promote_to_admin(user_fixture())
end
describe "Index (public)" do
test "lists beacons without logging in", %{conn: conn} do
beacon = beacon_fixture(user_fixture())
{:ok, _view, html} = live(conn, ~p"/beacons")
assert html =~ "Beacons"
assert html =~ beacon.callsign
end
test "non-admin does not see the New Beacon button", %{conn: conn} do
user = user_fixture()
conn = log_in_user(conn, user)
{:ok, _view, html} = live(conn, ~p"/beacons")
refute html =~ "New Beacon"
end
test "admin sees the New Beacon button", %{conn: conn} do
conn = log_in_user(conn, admin_user_fixture())
{:ok, _view, html} = live(conn, ~p"/beacons")
assert html =~ "New Beacon"
end
end
describe "Show (public)" do
test "renders beacon details without logging in", %{conn: conn} do
beacon = beacon_fixture(user_fixture())
{:ok, _view, html} = live(conn, ~p"/beacons/#{beacon}")
assert html =~ beacon.callsign
assert html =~ "#{beacon.frequency_mhz}"
end
end
describe "Form (admin only)" do
test "redirects non-admin away from /beacons/new", %{conn: conn} do
user = user_fixture()
conn = log_in_user(conn, user)
assert {:error, {:redirect, %{to: "/"}}} = live(conn, ~p"/beacons/new")
end
test "redirects anonymous user away from /beacons/new", %{conn: conn} do
assert {:error, {:redirect, %{to: "/users/log-in"}}} = live(conn, ~p"/beacons/new")
end
test "admin creates a beacon", %{conn: conn} do
conn = log_in_user(conn, admin_user_fixture())
{:ok, form_live, _html} = live(conn, ~p"/beacons/new")
attrs = valid_beacon_attrs()
assert {:ok, _view, html} =
form_live
|> form("#beacon-form", beacon: attrs)
|> render_submit()
|> follow_redirect(conn, ~p"/beacons")
assert html =~ "Beacon created"
assert html =~ attrs.callsign
end
test "admin edits a beacon", %{conn: conn} do
admin = admin_user_fixture()
beacon = beacon_fixture(admin)
conn = log_in_user(conn, admin)
{:ok, form_live, _} = live(conn, ~p"/beacons/#{beacon}/edit")
assert {:ok, _view, html} =
form_live
|> form("#beacon-form", beacon: %{power_watts: 25.0})
|> render_submit()
|> follow_redirect(conn, ~p"/beacons")
assert html =~ "Beacon updated"
end
end
end