defmodule ToweropsWeb.TraceLive.IndexTest do use ToweropsWeb.ConnCase, async: true import Phoenix.LiveViewTest setup :register_and_log_in_user setup %{user: user} do {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Trace Org"}, user.id) %{organization: organization} end describe "mount + events" do test "renders the empty trace page", %{conn: conn} do assert {:ok, _view, html} = live(conn, ~p"/trace") assert html =~ "Trace" or html =~ "Search" end test "search with empty query keeps results empty", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/trace") _ = render_hook(view, "search", %{"query" => ""}) assert true end test "search with a non-matching query returns []", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/trace") _ = render_hook(view, "search", %{"query" => "absolutely-nothing-matches-this"}) assert true end test "select_result patches the URL with type+id params", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/trace") id = Ecto.UUID.generate() _ = render_hook(view, "select_result", %{"type" => "device", "id" => id}) assert true end test "clear resets state and patches back to /trace", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/trace?type=device&id=#{Ecto.UUID.generate()}") _ = render_hook(view, "clear", %{}) assert true end end describe "format helpers" do alias ToweropsWeb.TraceLive.Index test "type_badge_class covers known and unknown types" do assert Index.type_badge_class(:account) == "badge-primary" assert Index.type_badge_class(:inventory_item) == "badge-secondary" assert Index.type_badge_class(:site) == "badge-warning" assert Index.type_badge_class(:device) == "badge-accent" assert Index.type_badge_class(:access_point) == "badge-info" assert Index.type_badge_class(:totally_unknown) == "badge-ghost" end test "type_badge_label covers known and unknown" do assert Index.type_badge_label(:account) == "Account" assert Index.type_badge_label(:device) == "Device" assert Index.type_badge_label(:other) == "Unknown" end test "status_badge_class covers all branches" do assert Index.status_badge_class("active") == "badge-success" assert Index.status_badge_class("suspended") == "badge-warning" assert Index.status_badge_class("cancelled") == "badge-error" assert Index.status_badge_class("frob") == "badge-ghost" end test "device_status_color covers all branches" do assert Index.device_status_color(:up) =~ "green" assert Index.device_status_color(:down) =~ "red" assert Index.device_status_color(:other) =~ "gray" end test "format_speed covers all branches" do assert Index.format_speed(nil) == "—" assert Index.format_speed(2500) == "2.5 Gbps" assert Index.format_speed(100) == "100 Mbps" assert Index.format_speed("???") == "???" end test "format_relative_time covers all branches" do assert Index.format_relative_time(nil) == "—" assert Index.format_relative_time(DateTime.utc_now()) == "just now" assert Index.format_relative_time(DateTime.add(DateTime.utc_now(), -120, :second)) =~ "m ago" assert Index.format_relative_time(DateTime.add(DateTime.utc_now(), -7200, :second)) =~ "h ago" assert Index.format_relative_time(DateTime.add(DateTime.utc_now(), -200_000, :second)) =~ "d ago" end test "format_score, format_pct, format_ms cover branches" do assert Index.format_score(nil) == "—" assert Index.format_score(0.5) == "0.5" assert Index.format_score("x") == "x" assert Index.format_pct(nil) == "—" assert Index.format_pct(50.5) == "50.5%" assert Index.format_pct("x") == "x" assert Index.format_ms(nil) == "—" assert Index.format_ms(123) == "123.0 ms" assert Index.format_ms("x") == "x" end end describe "deep-link with trace data renders issues_callout" do test "trace_type=device with a real device renders the trace shell", %{conn: conn, organization: organization} do {:ok, site} = Towerops.Sites.create_site(%{name: "Trace Test Site", organization_id: organization.id}) {:ok, device} = Towerops.Devices.create_device(%{ name: "Trace Dev", ip_address: "10.10.10.1", site_id: site.id, organization_id: organization.id }) {:ok, _view, html} = live(conn, ~p"/trace?type=device&id=#{device.id}") # Either renders the trace card or the empty state. Both exercise # handle_params with type+id which calls Trace.assemble_trace/3. assert html =~ "Trace" or html =~ device.name end test "trace_type=site with a real site renders the trace shell", %{conn: conn, organization: organization} do {:ok, site} = Towerops.Sites.create_site(%{name: "Trace Site", organization_id: organization.id}) {:ok, _view, html} = live(conn, ~p"/trace?type=site&id=#{site.id}") assert html =~ "Trace" or html =~ site.name end test "trace_type=account with an unknown id still renders without crash", %{conn: conn} do {:ok, _view, html} = live(conn, ~p"/trace?type=account&id=#{Ecto.UUID.generate()}") assert html =~ "Trace" end end end