test: GlobalSearch keyboard nav + StatusPageLive mount + Coverages.Profile clutter polygons

This commit is contained in:
Graham McIntire 2026-05-08 13:23:13 -05:00
parent 09e9fd2f3b
commit 5af987035f
3 changed files with 124 additions and 0 deletions

View file

@ -94,4 +94,45 @@ defmodule Towerops.Coverages.ProfileTest do
assert_in_delta d, 96_000.0, 2_000.0
end
end
describe "sample/5 with clutter polygons" do
test "samples report a building when the great-circle path crosses one" do
# Flat 100m grid that the path will sample
grid = flat_grid(100.0)
# Path from (0.95, -0.95) to (0.05, -0.05) — diagonal across the grid
tx = {0.95, -0.95}
rx = {0.05, -0.05}
# A building polygon at the midpoint of the path with height 30 m
# Polygon coords are {lon, lat}, closed ring (last == first)
building = %{
height_m: 30.0,
coords: [
{-0.55, 0.45},
{-0.45, 0.45},
{-0.45, 0.55},
{-0.55, 0.55},
{-0.55, 0.45}
]
}
samples = Profile.sample(grid, tx, rx, 9, clutter: [building])
# 9 samples requested, should get exactly 9
assert length(samples) == 9
# At least one sample sits inside the polygon → ground (100) + building (30)
assert 130.0 in samples
end
test "samples include canopy max when canopy grid is provided" do
grid = flat_grid(50.0)
canopy = flat_grid(10.0)
samples = Profile.sample(grid, {0.95, -0.95}, {0.05, -0.05}, 5, canopy: canopy)
# All samples should be at least DEM height (50 m); canopy adds clutter on top.
assert Enum.all?(samples, &(&1 >= 50.0))
end
end
end

View file

@ -77,5 +77,55 @@ defmodule ToweropsWeb.Live.Components.GlobalSearchComponentTest do
assert html =~ "No results found"
end
test "close hides the overlay", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/dashboard")
view
|> element("#global-search")
|> render_hook("open", %{})
html =
view
|> element("#global-search")
|> render_hook("close", %{})
refute html =~ "Search devices"
end
test "ArrowDown / ArrowUp keyboard navigation cycles selected index",
%{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/dashboard")
view |> element("#global-search") |> render_hook("open", %{})
view |> element("#global-search") |> render_hook("search", %{"value" => "Core"})
# Arrows shouldn't crash even at boundaries
view |> element("#global-search") |> render_hook("keydown", %{"key" => "ArrowDown"})
view |> element("#global-search") |> render_hook("keydown", %{"key" => "ArrowDown"})
view |> element("#global-search") |> render_hook("keydown", %{"key" => "ArrowUp"})
# An unrelated key is a no-op
html =
view
|> element("#global-search")
|> render_hook("keydown", %{"key" => "Tab"})
assert html =~ "Core"
end
test "Enter on an empty result list is a no-op", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/dashboard")
view |> element("#global-search") |> render_hook("open", %{})
html =
view
|> element("#global-search")
|> render_hook("keydown", %{"key" => "Enter"})
# No navigation, view stays alive
assert is_binary(html)
assert Process.alive?(view.pid)
end
end
end

View file

@ -97,5 +97,38 @@ defmodule ToweropsWeb.StatusPageLiveTest do
{:ok, view, _html} = live(conn, ~p"/status/unknown-slug-12345")
refute has_element?(view, "#status-page")
end
test "renders the status page when slug exists", %{conn: conn} do
user = Towerops.AccountsFixtures.user_fixture()
{:ok, org} = Towerops.Organizations.create_organization(%{name: "SP Org"}, user.id)
{:ok, config} =
Towerops.StatusPages.create_config(%{
organization_id: org.id,
slug: "sp-#{System.unique_integer([:positive])}",
company_name: "Acme Co",
enabled: true
})
{:ok, _view, html} = live(conn, ~p"/status/#{config.slug}")
assert html =~ "Acme Co"
end
test ":status_updated PubSub message refreshes assigns", %{conn: conn} do
user = Towerops.AccountsFixtures.user_fixture()
{:ok, org} = Towerops.Organizations.create_organization(%{name: "Push Org"}, user.id)
{:ok, config} =
Towerops.StatusPages.create_config(%{
organization_id: org.id,
slug: "push-#{System.unique_integer([:positive])}",
company_name: "Push Inc",
enabled: true
})
{:ok, view, _html} = live(conn, ~p"/status/#{config.slug}")
send(view.pid, {:status_updated, %{}})
assert render(view) =~ "Push Inc"
end
end
end