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, equipment} = Towerops.Equipment.create_equipment(%{ name: "Test Router", ip_address: "192.168.1.1", site_id: site.id }) %{organization: organization, site: site, equipment: equipment} end describe "Index" do test "displays alerts page", %{conn: conn, organization: organization} do {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") assert html =~ "Alerts" assert html =~ "Monitor and acknowledge system alerts" end test "displays empty state when no alerts", %{conn: conn, organization: organization} do {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") assert html =~ "No alerts" end test "lists all alerts", %{conn: conn, organization: organization, equipment: equipment} do {:ok, _alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_down, triggered_at: DateTime.utc_now(), message: "Equipment is down" }) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") assert html =~ "Test Router" assert html =~ "Equipment is down" assert html =~ "Equipment Down" end test "filters active alerts", %{conn: conn, organization: organization, equipment: equipment} do # Create an active equipment_down alert {:ok, _active_alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_down, triggered_at: DateTime.utc_now(), message: "Equipment is down" }) # Create a recovery alert (equipment_up) {:ok, _recovery_alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_up, triggered_at: DateTime.utc_now(), message: "Equipment recovered" }) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/alerts?filter=active") # Should show equipment_down alert assert html =~ "Equipment is down" # Should NOT show equipment_up alert in active filter refute html =~ "Equipment recovered" end test "acknowledges an alert", %{conn: conn, organization: organization, equipment: equipment} do {:ok, alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_down, triggered_at: DateTime.utc_now(), message: "Equipment is down" }) {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") html = view |> element("button", "Acknowledge") |> render_click(%{"id" => alert.id}) assert html =~ "Alert acknowledged" end test "does not show acknowledge button for equipment_up alerts", %{ conn: conn, organization: organization, equipment: equipment } do {:ok, _alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_up, triggered_at: DateTime.utc_now(), message: "Equipment recovered" }) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") # Should not show acknowledge button for equipment_up alerts refute html =~ "Acknowledge" end test "does not show acknowledge button for resolved alerts", %{ conn: conn, organization: organization, equipment: equipment } do {:ok, alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_down, triggered_at: DateTime.utc_now(), message: "Equipment is down" }) # Resolve the alert Towerops.Alerts.resolve_alert(alert) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") assert html =~ "Resolved" refute html =~ "Acknowledge" end test "updates in real-time when new alert is created", %{ conn: conn, organization: organization, equipment: equipment } do {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") # Broadcast new alert event Phoenix.PubSub.broadcast( Towerops.PubSub, "alerts:new", {:new_alert, equipment.id, :equipment_down} ) # View should update assert render(view) end test "updates in real-time when alert is resolved", %{ conn: conn, organization: organization, equipment: equipment } do {:ok, alert} = Towerops.Alerts.create_alert(%{ equipment_id: equipment.id, alert_type: :equipment_down, triggered_at: DateTime.utc_now(), message: "Equipment is down" }) {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/alerts") # Resolve the alert and broadcast Towerops.Alerts.resolve_alert(alert) Phoenix.PubSub.broadcast( Towerops.PubSub, "alerts:resolved", {:alert_resolved, equipment.id, :equipment_down} ) # View should update assert render(view) end test "requires authentication", %{organization: organization} do conn = build_conn() {:error, redirect} = live(conn, ~p"/orgs/#{organization.slug}/alerts") assert {:redirect, %{to: path}} = redirect assert path == ~p"/users/log-in" end end end