prop/test/microwaveprop/propagation/daily_outlook_test.exs
Graham McIntire a6af6b115a
feat(map): 7-day outlook strip
Adds a compact seven-card horizontal strip to both mobile and desktop
map sidebars showing the per-day peak score at the viewport center
for the selected band. Cards are color-coded (emerald for 80+,
rose for bad) so the weekend verdict reads at a glance.

- Propagation.daily_outlook_at/3: groups point_forecast entries by
  UTC date, picks each day's peak, returns ascending order
- MapLive mounts with today's outlook for the initial center; the
  select_band handler refreshes it from the viewport midpoint so the
  strip tracks the user's current band and rough location
- Empty-state message covers the case where no extended-horizon
  scores have landed yet (fresh deploy, or before the first GEFS
  run completes)

This is the consumer of the GEFS pipeline — once the cron starts
running and f024-f168 scores accumulate, days 2-7 of the strip
populate automatically.
2026-04-18 14:46:44 -05:00

59 lines
1.8 KiB
Elixir

defmodule Microwaveprop.Propagation.DailyOutlookTest do
use Microwaveprop.DataCase, async: false
alias Microwaveprop.Propagation
alias Microwaveprop.Propagation.ScoreCache
setup do
ScoreCache.clear()
on_exit(fn -> ScoreCache.clear() end)
:ok
end
describe "daily_outlook_at/3" do
test "returns an empty list when no scores have been written" do
assert Propagation.daily_outlook_at(32.9, -97.0, days: 3) == []
end
test "groups scores by UTC date and picks the peak per day" do
# Use a lat on the grid: snap(32.9) = 32.875 (step 0.125). Write at
# the snapped coords so point_forecast's internal snap-to-grid finds
# the scores on disk.
lat = 32.875
lon = -97.0
band = 10_000
# Day A: 5Z @ 40, 17Z @ 80 → peak 80
# Day B: 5Z @ 60 → peak 60
day_a_1 = ~U[2026-04-20 05:00:00Z]
day_a_2 = ~U[2026-04-20 17:00:00Z]
day_b_1 = ~U[2026-04-21 05:00:00Z]
Propagation.replace_scores(
[%{lat: lat, lon: lon, valid_time: day_a_1, band_mhz: band, score: 40, factors: nil}],
day_a_1
)
Propagation.replace_scores(
[%{lat: lat, lon: lon, valid_time: day_a_2, band_mhz: band, score: 80, factors: nil}],
day_a_2
)
Propagation.replace_scores(
[%{lat: lat, lon: lon, valid_time: day_b_1, band_mhz: band, score: 60, factors: nil}],
day_b_1
)
outlook = Propagation.daily_outlook_at(lat, lon, band_mhz: band, days: 30)
# The helper returns entries in ascending date order.
assert length(outlook) >= 2
day_a = Enum.find(outlook, &(&1.date == ~D[2026-04-20]))
day_b = Enum.find(outlook, &(&1.date == ~D[2026-04-21]))
assert day_a.peak_score == 80
assert day_b.peak_score == 60
end
end
end