defmodule MicrowavepropWeb.WeatherCaMapLiveTest do # async: false because we touch the shared scalar / profile dirs. use MicrowavepropWeb.ConnCase, async: false import Phoenix.LiveViewTest alias Microwaveprop.Propagation.ProfilesFile alias Microwaveprop.Weather.GridCache alias Microwaveprop.Weather.ScalarFile setup do GridCache.clear() on_exit(fn -> GridCache.clear() ProfilesFile.prune_older_than(~U[2099-12-31 23:59:59Z]) end) :ok end test "mounts at /weather-ca with Canadian default viewport", %{conn: conn} do {:ok, _lv, html} = live(conn, ~p"/weather-ca") # Default viewport is centered roughly on central Canada at a low # zoom — different from /weather's DFW@z7. The exact numbers are # asserted so a routing accident (mounting WeatherMapLive at this # path by mistake) is caught. assert html =~ ~s(data-initial-lat="55.0") assert html =~ ~s(data-initial-lon="-100.0") assert html =~ ~s(data-initial-zoom="4") end test "renders the weather map element with data-source=hrdps", %{conn: conn} do {:ok, _lv, html} = live(conn, ~p"/weather-ca") # The JS hook reads data-source and appends &source=hrdps to its cell # fetches. Without this attribute the page would silently fall back # to HRRR-only reads and never show Canadian data. assert html =~ ~s(data-source="hrdps") end test "viewport_changed event push_patches /weather-ca, not /weather", %{conn: conn} do {:ok, lv, _html} = live(conn, ~p"/weather-ca") render_hook(lv, "viewport_changed", %{"lat" => 60.0, "lon" => -110.0, "zoom" => 5}) assert_patch(lv, "/weather-ca?layer=temperature&lat=60.0&lon=-110.0&zoom=5") end test "select_layer push_patches a /weather-ca URL", %{conn: conn} do {:ok, lv, _html} = live(conn, ~p"/weather-ca") render_hook(lv, "select_layer", %{"layer" => "pwat"}) assert_patch(lv, "/weather-ca?layer=pwat&lat=55.0&lon=-100.0&zoom=4") end test "shows HRDPS valid_times even when several hours old (no 1h cutoff)", %{conn: conn} do # HRDPS publishes 4x/day with ~3-4h latency, plus our chain step # takes ~13 min. The 1-hour cutoff /weather uses would routinely # leave /weather-ca empty between fresh chain steps. Hand-write a # 4-hour-old HRDPS chunk and confirm it lands in the timeline. now = DateTime.utc_now() |> DateTime.truncate(:second) |> Map.put(:minute, 0) |> Map.put(:second, 0) stale_t = DateTime.add(now, -4 * 3600, :second) hrdps_dir = ScalarFile.dir_for_hrdps(stale_t) File.mkdir_p!(hrdps_dir) payload = Msgpax.pack!( [%{"lat" => 53.0, "lon" => -60.0, "valid_time" => DateTime.to_iso8601(stale_t), "temperature" => 8.0}], iodata: false ) File.write!(Path.join(hrdps_dir, "10_-12.mp.gz"), :zlib.gzip(payload)) on_exit(fn -> File.rm_rf!(hrdps_dir) end) {:ok, _lv, html} = live(conn, ~p"/weather-ca") iso = DateTime.to_iso8601(stale_t) assert html =~ iso, "4-hour-old HRDPS valid_time should appear in /weather-ca timeline" end end