defmodule MicrowavepropWeb.QsoLiveTest do use MicrowavepropWeb.ConnCase, async: true import Phoenix.LiveViewTest alias Microwaveprop.Radio.Qso alias Microwaveprop.Repo defp create_qso(attrs \\ %{}) do default = %{ station1: "W5XD", station2: "K5TR", qso_timestamp: ~U[2026-03-28 18:00:00Z], mode: "CW", band: Decimal.new("1296"), grid1: "EM12", grid2: "EM00", pos1: %{"lat" => 32.9, "lon" => -97.0}, pos2: %{"lat" => 30.3, "lon" => -97.7}, distance_km: Decimal.new("295") } {:ok, qso} = %Qso{} |> Qso.changeset(Map.merge(default, attrs)) |> Repo.insert() qso end describe "Index" do test "renders page with QSOs heading", %{conn: conn} do {:ok, _lv, html} = live(conn, ~p"/qsos") assert html =~ "QSOs" end test "table shows QSO data", %{conn: conn} do create_qso() {:ok, _lv, html} = live(conn, ~p"/qsos") assert html =~ "W5XD" assert html =~ "K5TR" assert html =~ "CW" assert html =~ "1296" end test "row links to detail page", %{conn: conn} do qso = create_qso() {:ok, _lv, html} = live(conn, ~p"/qsos") assert html =~ ~p"/qsos/#{qso.id}" end test "clicking sort header changes URL params", %{conn: conn} do create_qso(%{station1: "ZZ9ZZ"}) create_qso(%{station1: "AA1AA"}) {:ok, lv, _html} = live(conn, ~p"/qsos") lv |> element("span[phx-click=sort][phx-value-field=station1]") |> render_click() assert_patch(lv, "/qsos?sort_by=station1&sort_order=asc") end test "sort params order the table", %{conn: conn} do create_qso(%{station1: "ZZ9ZZ"}) create_qso(%{station1: "AA1AA"}) {:ok, _lv, html} = live(conn, ~p"/qsos?sort_by=station1&sort_order=asc") # AA1AA should appear before ZZ9ZZ aa_pos = html |> :binary.match("AA1AA") |> elem(0) zz_pos = html |> :binary.match("ZZ9ZZ") |> elem(0) assert aa_pos < zz_pos end test "clicking same sort header toggles direction", %{conn: conn} do create_qso() {:ok, lv, _html} = live(conn, ~p"/qsos?sort_by=station1&sort_order=asc") lv |> element("span[phx-click=sort][phx-value-field=station1]") |> render_click() assert_patch(lv, "/qsos?sort_by=station1&sort_order=desc") end test "pagination works", %{conn: conn} do for i <- 1..25 do ts = DateTime.add(~U[2026-01-01 00:00:00Z], i * 3600, :second) create_qso(%{qso_timestamp: ts}) end {:ok, _lv, html} = live(conn, ~p"/qsos") assert html =~ "Page 1 of 2" {:ok, _lv, html2} = live(conn, ~p"/qsos?page=2") assert html2 =~ "Page 2 of 2" end end describe "Show" do test "renders QSO detail fields", %{conn: conn} do qso = create_qso() {:ok, _lv, html} = live(conn, ~p"/qsos/#{qso.id}") assert html =~ "W5XD" assert html =~ "K5TR" assert html =~ "CW" assert html =~ "1296" assert html =~ "EM12" assert html =~ "EM00" end test "shows surface observations section", %{conn: conn} do qso = create_qso() {:ok, _lv, html} = live(conn, ~p"/qsos/#{qso.id}") assert html =~ "Surface Observations" end test "shows sounding section", %{conn: conn} do qso = create_qso() {:ok, _lv, html} = live(conn, ~p"/qsos/#{qso.id}") assert html =~ "Soundings" end test "shows solar index section", %{conn: conn} do qso = create_qso() {:ok, _lv, html} = live(conn, ~p"/qsos/#{qso.id}") assert html =~ "Solar Conditions" end test "renders with sort assigns", %{conn: conn} do qso = create_qso() {:ok, lv, html} = live(conn, ~p"/qsos/#{qso.id}") # Page renders without error assert html =~ "Surface Observations" assert html =~ "Soundings" # Sort assigns are initialized (no crash on render) assert render(lv) =~ qso.station1 end test "raises for bad UUID", %{conn: conn} do assert_raise Ecto.NoResultsError, fn -> live(conn, ~p"/qsos/#{Ecto.UUID.generate()}") end end end end