defmodule ToweropsWeb.AlertLive.IndexTest do use ToweropsWeb.ConnCase import Phoenix.LiveViewTest setup :register_and_log_in_user setup %{user: user} do {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id) {:ok, site} = Towerops.Sites.create_site(%{ name: "Test Site", organization_id: organization.id }) {:ok, device} = Towerops.Devices.create_device(%{ name: "Test Router", ip_address: "192.168.1.1", site_id: site.id, organization_id: organization.id }) %{organization: organization, site: site, device: device} end describe "Index" do test "displays alerts page", %{conn: conn, organization: _organization} do {:ok, _view, html} = live(conn, ~p"/alerts") assert html =~ "Alerts" end test "displays empty state when no alerts", %{conn: conn, organization: _organization} do {:ok, _view, html} = live(conn, ~p"/alerts") assert html =~ "No active alerts" end @tag :skip test "lists all alerts", %{conn: conn, organization: _organization, device: device} do {:ok, _alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) {:ok, _view, html} = live(conn, ~p"/alerts") assert html =~ "Test Router" assert html =~ "Device is down" # Alert type badge shows "Down" for device_down alerts assert html =~ "DOWN" end test "filters critical alerts", %{conn: conn, organization: _organization, device: device} do # Create a critical device_down alert (unresolved) {:ok, _active_alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) # Create a recovery alert (device_up) {:ok, _recovery_alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_up", triggered_at: DateTime.utc_now(), message: "Device recovered" }) {:ok, _view, html} = live(conn, ~p"/alerts?filter=critical") # Should show device_down alert assert html =~ "Device is down" # Should NOT show device_up alert in critical filter refute html =~ "Device recovered" end @tag :skip test "acknowledges an alert", %{conn: conn, organization: _organization, device: device} do {:ok, alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) {:ok, view, _html} = live(conn, ~p"/alerts") html = view |> element("button", "Ack") |> render_click(%{"id" => alert.id}) assert html =~ "Alert acknowledged" end test "does not show acknowledge button for device_up alerts", %{ conn: conn, organization: _organization, device: device } do {:ok, _alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_up", triggered_at: DateTime.utc_now(), message: "Device recovered" }) {:ok, _view, html} = live(conn, ~p"/alerts") # Should not show acknowledge button for device_up alerts # The button text in the template is "Ack" (short for Acknowledge) refute html =~ "phx-click=\"acknowledge\"" end test "updates in real-time when new alert is created", %{ conn: conn, organization: organization, device: device } do {:ok, view, _html} = live(conn, ~p"/alerts") # Broadcast new alert event on org-scoped topic Phoenix.PubSub.broadcast( Towerops.PubSub, "alerts:org:#{organization.id}:new", {:new_alert, device.id, :device_down} ) # View should update assert render(view) end test "updates in real-time when alert is resolved", %{ conn: conn, organization: organization, device: device } do {:ok, alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) {:ok, view, _html} = live(conn, ~p"/alerts") # Resolve the alert and broadcast Towerops.Alerts.resolve_alert(alert) Phoenix.PubSub.broadcast( Towerops.PubSub, "alerts:org:#{organization.id}:resolved", {:alert_resolved, device.id, :device_down} ) # View should update assert render(view) end test "requires authentication", %{organization: _organization} do conn = build_conn() {:error, redirect} = live(conn, ~p"/alerts") assert {:redirect, %{to: path}} = redirect assert path == ~p"/users/log-in" end test "shows site subscriber context when Gaiia mapped", %{ conn: conn, organization: organization, site: site, device: device } do {:ok, _alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) {:ok, _} = Towerops.Gaiia.upsert_network_site(organization.id, %{ gaiia_id: "ns-alert-test", name: "Tower", account_count: 75, total_mrr: Decimal.new("3750.00"), site_id: site.id }) {:ok, _view, html} = live(conn, ~p"/alerts") assert html =~ "75" end test "hides site subscriber context when no Gaiia mapping", %{ conn: conn, device: device } do {:ok, _alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) {:ok, _view, html} = live(conn, ~p"/alerts") refute html =~ "subscribers" refute html =~ "MRR" end end end