defmodule ToweropsWeb.InsightsLive.IndexEventsTest do @moduledoc """ Drives event handlers in the Insights LiveView (filter, dismiss, toggle_select, select_all, deselect_all, bulk_dismiss). """ use ToweropsWeb.ConnCase, async: true import Phoenix.LiveViewTest alias Towerops.Preseem.Insight alias Towerops.Repo setup :register_and_log_in_user setup %{user: user} do {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Insights Org"}, user.id) insights = for i <- 1..3 do {:ok, insight} = Repo.insert( Insight.changeset(%Insight{}, %{ organization_id: organization.id, type: "snmp_cpu_high", urgency: "warning", status: "active", channel: "proactive", title: "Insight #{i}", source: "preseem" }) ) insight end %{organization: organization, insights: insights} end describe "filter event" do test "patches the URL with chosen filters", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "filter", %{ "source" => "preseem", "urgency" => "warning", "status" => "active" }) assert true end test "drops empty filter params", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "filter", %{"source" => "", "urgency" => "", "status" => ""}) assert true end end describe "select / toggle / deselect events" do test "select_all + deselect_all flow", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "select_all", %{}) _ = render_hook(view, "deselect_all", %{}) assert true end test "toggle_select flips membership of an id", %{conn: conn, insights: [i1 | _]} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "toggle_select", %{"id" => i1.id}) _ = render_hook(view, "toggle_select", %{"id" => i1.id}) assert true end end describe "dismiss + bulk_dismiss" do test "dismiss marks a single insight as dismissed", %{conn: conn, insights: [i1 | _]} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "dismiss", %{"id" => i1.id}) reloaded = Repo.get!(Insight, i1.id) assert reloaded.status == "dismissed" end test "bulk_dismiss is a no-op when nothing selected", %{conn: conn} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "bulk_dismiss", %{}) assert true end test "bulk_dismiss clears selection and dismisses all selected", %{conn: conn, insights: [i1, i2 | _]} do {:ok, view, _html} = live(conn, ~p"/insights") _ = render_hook(view, "toggle_select", %{"id" => i1.id}) _ = render_hook(view, "toggle_select", %{"id" => i2.id}) _ = render_hook(view, "bulk_dismiss", %{}) assert Repo.get!(Insight, i1.id).status == "dismissed" assert Repo.get!(Insight, i2.id).status == "dismissed" end end describe "LLM enrichment rendering" do test "shows llm_summary, recommended_action, and model when present", %{ conn: conn, organization: organization } do {:ok, _enriched} = Repo.insert( Insight.changeset(%Insight{}, %{ organization_id: organization.id, type: "wireless_signal_weak", urgency: "warning", status: "active", channel: "proactive", title: "Enriched insight", source: "snmp", llm_summary: "AP has 3 clients pinned to MCS0; downstream is congested.", recommended_action: "Re-aim CPE at -82 dBm or move it to AP-7.", llm_model: "deepseek-v4-pro", llm_enriched_at: ~U[2026-05-09 12:00:00Z] }) ) {:ok, _view, html} = live(conn, ~p"/insights") assert html =~ "AP has 3 clients pinned to MCS0; downstream is congested." assert html =~ "Re-aim CPE at -82 dBm or move it to AP-7." assert html =~ "deepseek-v4-pro" end test "does not render the summary block when llm_summary is nil", %{conn: conn} do {:ok, _view, html} = live(conn, ~p"/insights") refute html =~ "Recommended action:" refute html =~ "AI-generated" end end end