defmodule ToweropsWeb.CoverageLive.ShowTest do use ToweropsWeb.ConnCase import Phoenix.LiveViewTest import Towerops.CoveragesFixtures import Towerops.OrganizationsFixtures alias Towerops.Coverages setup :register_and_log_in_user setup %{conn: conn, user: user} do org = organization_fixture(user.id) site = site_fixture(org.id, %{latitude: 30.27, longitude: -97.74}) conn = Plug.Conn.put_session(conn, :current_organization_id, org.id) %{conn: conn, org: org, site: site} end describe "mount" do test "renders coverage details for a draft coverage", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id, %{name: "Hilltop Sector"}) {:ok, _view, html} = live(conn, ~p"/coverage/#{cov.id}") assert html =~ "Hilltop Sector" assert html =~ "No heatmap available yet" end test "renders the parameters drawer when coverage is ready", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id, %{name: "ReadyOne"}) {:ok, _ready} = Coverages.mark_status(cov, "ready", %{ png_path: "/coverage/#{org.id}/#{cov.id}/rssi.png", raster_path: "/coverage/#{org.id}/#{cov.id}/rssi.tif", bbox_min_lat: 30.0, bbox_min_lon: -98.0, bbox_max_lat: 30.5, bbox_max_lon: -97.5 }) {:ok, _view, html} = live(conn, ~p"/coverage/#{cov.id}") assert html =~ "Parameters" end test "shows queued banner for queued coverage", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, queued} = Coverages.mark_status(cov, "queued", %{}) {:ok, _view, html} = live(conn, ~p"/coverage/#{queued.id}") assert html =~ "queued" end test "shows failed banner with error message", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, failed} = Coverages.mark_status(cov, "failed", %{error_message: "test failure"}) {:ok, _view, html} = live(conn, ~p"/coverage/#{failed.id}") assert html =~ "test failure" end test "404 for unknown coverage", %{conn: conn} do assert_raise Ecto.NoResultsError, fn -> live(conn, ~p"/coverage/#{Ecto.UUID.generate()}") end end test "requires authentication" do conn = build_conn() assert {:error, {:redirect, %{to: path}}} = live(conn, ~p"/coverage/#{Ecto.UUID.generate()}") assert path =~ "/users/log-in" end end describe "events" do test "toggle_params hides and re-shows the parameters drawer", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, view, html} = live(conn, ~p"/coverage/#{cov.id}") assert html =~ "Hide details" html = render_click(view, "toggle_params", %{}) assert html =~ "Details" refute html =~ "Hide details" end test "set_probe_units switches between ft and m", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, view, _html} = live(conn, ~p"/coverage/#{cov.id}") assert render_click(view, "set_probe_units", %{"units" => "m"}) assert render_click(view, "set_probe_units", %{"units" => "ft"}) end test "delete removes the coverage and redirects", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id, %{name: "DoomedCoverage"}) {:ok, view, _html} = live(conn, ~p"/coverage/#{cov.id}") result = render_click(view, "delete", %{}) assert {:error, {:live_redirect, %{to: "/coverage"}}} = result assert nil == Coverages.get_coverage(org.id, cov.id) end test "recompute queues compute and refreshes status", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, view, _html} = live(conn, ~p"/coverage/#{cov.id}") html = render_click(view, "recompute", %{}) assert html =~ "queued" end test "probe_point handler stores point in assigns", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, view, _html} = live(conn, ~p"/coverage/#{cov.id}") assert render_hook(view, "probe_point", %{"lat" => "30.27", "lon" => "-97.74"}) end test "close_probe clears the active probe", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, view, _html} = live(conn, ~p"/coverage/#{cov.id}") _ = render_hook(view, "probe_point", %{"lat" => "30.27", "lon" => "-97.74"}) assert render_click(view, "close_probe", %{}) end end describe "coverage_lat / coverage_lon helpers" do alias ToweropsWeb.CoverageLive.Show test "coverage_lat returns the coverage's latitude when present", %{org: org, site: site} do cov = coverage_fixture(org.id, site.id) assert is_number(Show.coverage_lat(cov)) or Show.coverage_lat(cov) == nil end test "coverage_lon returns the coverage's longitude when present", %{org: org, site: site} do cov = coverage_fixture(org.id, site.id) assert is_number(Show.coverage_lon(cov)) or Show.coverage_lon(cov) == nil end end describe "format helpers" do alias ToweropsWeb.CoverageLive.Show test "format_ft converts metres to feet" do assert Show.format_ft(30.0) == "98 ft" assert Show.format_ft(nil) == "—" end test "format_mi converts metres to miles" do assert Show.format_mi(1609.344) == "1.0 mi" assert Show.format_mi(nil) == "—" end test "format_ghz converts MHz to GHz" do assert Show.format_ghz(5800) == "5.8 GHz" assert Show.format_ghz(nil) == "—" end test "status_badge_class maps known statuses" do assert Show.status_badge_class("ready") =~ "bg-green" assert Show.status_badge_class("failed") =~ "bg-red" assert Show.status_badge_class("computing") =~ "bg-yellow" assert Show.status_badge_class("queued") =~ "bg-blue" assert Show.status_badge_class("draft") =~ "bg-gray" assert Show.status_badge_class("anything-else") =~ "bg-gray" end end describe "handle_info :coverage_status" do test "coverage_status update reloads the coverage and pushes list-changed", %{conn: conn, org: org, site: site} do cov = coverage_fixture(org.id, site.id) {:ok, view, _html} = live(conn, ~p"/coverage/#{cov.id}") send(view.pid, {:coverage_status, "ready", %{}}) # Force a render to ensure the handler ran html = render(view) assert html =~ cov.name end end end