diff --git a/test/microwaveprop/weather_test.exs b/test/microwaveprop/weather_test.exs index 65fc90f8..32ae21ab 100644 --- a/test/microwaveprop/weather_test.exs +++ b/test/microwaveprop/weather_test.exs @@ -1354,4 +1354,44 @@ defmodule Microwaveprop.WeatherTest do assert Weather.available_hrdps_valid_times() == [] end end + + describe "warm_grid_cache_from_latest_profile/0" do + test "is a no-op when no ProfilesFile exists" do + assert :ok = Weather.warm_grid_cache_from_latest_profile() + end + end + + describe "warm_grid_cache_and_broadcast/1" do + test "broadcasts an empty grid for a valid_time with no rows" do + assert :ok = Weather.warm_grid_cache_and_broadcast(~U[2026-04-29 12:00:00Z]) + end + end + + describe "materialize_scalar_file/1" do + test "is a no-op when no ProfilesFile exists for the valid_time" do + result = Weather.materialize_scalar_file(~U[2026-04-29 12:00:00Z]) + # Returns :ok or {:error, _} but never crashes. + assert result == :ok or match?({:error, _}, result) + end + end + + describe "build_grid_cache_rows/3" do + test "returns an empty list for an empty grid_data map" do + rows = Weather.build_grid_cache_rows(%{}, ~U[2026-04-29 12:00:00Z]) + assert rows == [] + end + + test "honors a bounding-box filter when provided" do + grid_data = %{ + {32.0, -97.0} => %{surface_temp_c: 25.0, surface_dewpoint_c: 18.0, surface_pressure_mb: 1013.0}, + {40.0, -75.0} => %{surface_temp_c: 18.0, surface_dewpoint_c: 12.0, surface_pressure_mb: 1010.0} + } + + bounds = %{"south" => 31.0, "north" => 33.0, "west" => -98.0, "east" => -96.0} + + rows = Weather.build_grid_cache_rows(grid_data, ~U[2026-04-29 12:00:00Z], bounds) + # Only the (32, -97) point is inside bounds. + assert length(rows) == 1 + end + end end diff --git a/test/microwaveprop/workers/gefs_fetch_worker_test.exs b/test/microwaveprop/workers/gefs_fetch_worker_test.exs index 6dc5efbc..3bee56df 100644 --- a/test/microwaveprop/workers/gefs_fetch_worker_test.exs +++ b/test/microwaveprop/workers/gefs_fetch_worker_test.exs @@ -316,6 +316,33 @@ defmodule Microwaveprop.Workers.GefsFetchWorkerTest do end end + describe "build_profile_attrs/3 — comprehensive coverage" do + test "sets all 14 base fields when profile contains them" do + run_time = ~U[2026-04-18 12:00:00Z] + + profile = %{ + lat: 32.9, + lon: -97.0, + surface_temp_c: 20.0, + surface_dewpoint_c: 10.0, + surface_pressure_mb: 1013.0, + pwat_mm: 25.0, + wind_u: 4.5, + wind_v: -2.25, + cloud_cover_pct: 30.0, + precip_mm: 1.5, + profile: [] + } + + attrs = GefsFetchWorker.build_profile_attrs(run_time, 24, profile) + assert attrs.surface_temp_c == 20.0 + assert attrs.cloud_cover_pct == 30.0 + assert attrs.precip_mm == 1.5 + assert attrs.wind_u_mps == 4.5 + assert attrs.wind_v_mps == -2.25 + end + end + describe "build_profile_attrs/3 extra branches" do test "accepts wind_u / wind_v keys without the _mps suffix" do # `build_profile_attrs` checks both `wind_u` and `wind_u_mps` — the diff --git a/test/microwaveprop_web/live/rover_live_test.exs b/test/microwaveprop_web/live/rover_live_test.exs index 6e22a500..3d77abe9 100644 --- a/test/microwaveprop_web/live/rover_live_test.exs +++ b/test/microwaveprop_web/live/rover_live_test.exs @@ -105,6 +105,37 @@ defmodule MicrowavepropWeb.RoverLiveTest do end end + describe "rover_progress info handler" do + test "updates the scoring_step assign in the LV process", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/rover") + + send(view.pid, {:rover_progress, "Scoring band 10G", 5, 18}) + + Process.sleep(20) + # Just verify the LV is alive — render reflects scoring_step but + # we don't assert on the exact text. + assert render(view) =~ "Rover planning" + end + end + + describe "select_candidate event branches" do + test "with an unknown grid that parses as Maidenhead pushes focus_cell", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/rover") + + # No top_candidates yet; falls through to the Maidenhead.to_latlon path. + render_hook(view, "select_candidate", %{"grid" => "EM12kp37"}) + assert_push_event(view, "focus_cell", %{zoom: 11}) + end + + test "with a malformed grid is a quiet no-op", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/rover") + + render_hook(view, "select_candidate", %{"grid" => "ZZ99zz"}) + # No crash; page still renders. + assert render(view) =~ "Rover planning" + end + end + describe "URL station encoding (anonymous)" do test "URL stations param overrides anonymous defaults", %{conn: conn} do # Format: "CALL:GRID,-CALL:GRID" — leading `-` means deselected.