- Pskr.Client: 0% -> 18% (init/standby/handle_info/terminate) - RoverPlanningLive.PathShow: 0% -> 82% (mount/load_path) - Rover.CandidateDetail: 0% -> partial (summarize/5 with stations) - Mix.Tasks.Weather.RebatchAsos: 0% -> covered (wrapper run/1) - HrrrNativeClient: 57% -> 67% (fetch_native_duct_grid error paths) - RoverLive: 40% -> 48% (toggle/delete/update_station_grid logged-in) - PathLive: 62% -> 63% (path_forecast_detail + rover_path_id branches) - PathCompute: 64% -> 64% (compute/4 full pipeline + resolve_location) - SkewtLive: 29% -> 31% (search/select_time event no-ops) - SkewtLocationResolver: 38% -> 60%+ (callsign cache + error paths) 3557 tests passing.
161 lines
5 KiB
Elixir
161 lines
5 KiB
Elixir
defmodule MicrowavepropWeb.SkewtLiveTest do
|
|
use MicrowavepropWeb.ConnCase, async: false
|
|
|
|
import Phoenix.LiveViewTest
|
|
|
|
alias Microwaveprop.Weather.HrrrProfile
|
|
|
|
describe "with HRRR profile data near the queried location" do
|
|
setup do
|
|
profile_data = [
|
|
%{"pres" => 1000.0, "hght" => 110, "tmpc" => 25.0, "dwpc" => 18.0},
|
|
%{"pres" => 925.0, "hght" => 770, "tmpc" => 18.0, "dwpc" => 12.0},
|
|
%{"pres" => 850.0, "hght" => 1500, "tmpc" => 14.0, "dwpc" => 8.0},
|
|
%{"pres" => 700.0, "hght" => 3000, "tmpc" => 0.0, "dwpc" => -10.0},
|
|
%{"pres" => 500.0, "hght" => 5500, "tmpc" => -20.0, "dwpc" => -30.0}
|
|
]
|
|
|
|
# Insert near EM12kp (32.646, -97.125)
|
|
now = DateTime.truncate(DateTime.utc_now(), :second)
|
|
|
|
%HrrrProfile{}
|
|
|> HrrrProfile.changeset(%{
|
|
valid_time: now,
|
|
run_time: now,
|
|
lat: 32.65,
|
|
lon: -97.12,
|
|
profile: profile_data,
|
|
hpbl_m: 1500.0,
|
|
pwat_mm: 25.0,
|
|
surface_temp_c: 25.0,
|
|
surface_dewpoint_c: 18.0,
|
|
surface_pressure_mb: 1013.0,
|
|
surface_refractivity: 320.5,
|
|
min_refractivity_gradient: -45.0,
|
|
ducting_detected: false
|
|
})
|
|
|> Microwaveprop.Repo.insert!()
|
|
|
|
:ok
|
|
end
|
|
|
|
test "renders the time selector when valid_times list is non-empty", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
_ = render_async(view)
|
|
# We can't reliably assert HRRR data renders since fetch_rich_cell
|
|
# tries an HTTP call that fails — but the page should not crash.
|
|
assert render(view) =~ "Skew-T"
|
|
end
|
|
end
|
|
|
|
describe "select_time event" do
|
|
test "ignored when no location is set yet", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt")
|
|
|
|
# No location resolved → select_time falls through to the no-op.
|
|
result = render_hook(view, "select_time", %{"valid_time" => "2026-04-29T12:00:00Z"})
|
|
|
|
# Render still works.
|
|
assert result =~ "Skew-T"
|
|
end
|
|
|
|
test "ignored when valid_time is unparseable", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
render_async(view)
|
|
|
|
result = render_hook(view, "select_time", %{"valid_time" => "not-a-timestamp"})
|
|
|
|
assert result =~ "Skew-T"
|
|
end
|
|
end
|
|
|
|
describe "search event" do
|
|
test "patches URL when user submits the form", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt")
|
|
|
|
render_hook(view, "search", %{"q" => "EM13"})
|
|
assert render_async(view) =~ "EM13"
|
|
end
|
|
end
|
|
|
|
describe "GET /skewt" do
|
|
test "renders search bar with no results when no query is supplied", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/skewt")
|
|
|
|
assert html =~ "Skew-T-Log-P"
|
|
assert html =~ ~s|placeholder="EM12kp|
|
|
refute html =~ "viewBox=\"0 0 720"
|
|
end
|
|
|
|
test "initial render with a URL query shows the page chrome + a loading indicator", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
assert html =~ "Skew-T-Log-P"
|
|
assert html =~ ~s|placeholder="EM12kp|
|
|
assert html =~ "Resolving location"
|
|
refute html =~ "EM12KP"
|
|
end
|
|
|
|
test "after the async completes the resolved location label appears", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
html = render_async(view)
|
|
|
|
assert html =~ "EM12KP"
|
|
assert html =~ "32.646"
|
|
assert html =~ "-97.125"
|
|
refute html =~ "Resolving location"
|
|
end
|
|
|
|
test "submitting the form patches the URL with the query", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt")
|
|
|
|
view |> form("form", q: "EM12") |> render_submit()
|
|
|
|
assert render_async(view) =~ "EM12"
|
|
end
|
|
|
|
test "shows info alert when no HRRR profiles are stored", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
html = render_async(view)
|
|
|
|
assert html =~ "No HRRR profiles are currently stored"
|
|
assert has_element?(view, ".alert.alert-info")
|
|
end
|
|
|
|
test "time selector is not shown when there are no valid times", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
render_async(view)
|
|
|
|
refute has_element?(view, "button[phx-click=select_time]")
|
|
end
|
|
|
|
test "loading indicator visible while async is in flight", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
assert has_element?(view, ".loading")
|
|
assert render(view) =~ "Resolving location"
|
|
end
|
|
|
|
test "on successful async the loading state is cleared and location shown", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
html = render_async(view)
|
|
|
|
refute html =~ "Resolving location"
|
|
assert html =~ "EM12KP"
|
|
assert html =~ "32.646"
|
|
end
|
|
|
|
test "coordinates are formatted with 3 decimal places", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/skewt?q=EM12kp")
|
|
|
|
html = render_async(view)
|
|
|
|
assert html =~ "32.646"
|
|
assert html =~ "-97.125"
|
|
end
|
|
end
|
|
end
|