aprs.me/test/aprsme_web/live/weather_live/callsign_view_test.exs

144 lines
4.6 KiB
Elixir

defmodule AprsmeWeb.WeatherLive.CallsignViewTest do
use AprsmeWeb.ConnCase
import Phoenix.LiveViewTest
alias AprsmeWeb.WeatherLive.CallsignView
describe "mount via HTTP" do
test "renders the weather view for a callsign", %{conn: conn} do
{:ok, _lv, html} = live(conn, ~p"/weather/N0CALL", on_error: :warn)
assert html =~ "N0CALL"
end
test "normalizes lowercase callsign to uppercase", %{conn: conn} do
{:ok, _lv, html} = live(conn, ~p"/weather/k1abc", on_error: :warn)
assert html =~ "K1ABC"
end
end
describe "has_weather_field?/2" do
test "returns false for missing fields" do
refute CallsignView.has_weather_field?(%{}, :temperature)
end
test "returns false for nil values" do
refute CallsignView.has_weather_field?(%{temperature: nil}, :temperature)
end
test "returns true for numeric values" do
assert CallsignView.has_weather_field?(%{temperature: 72.5}, :temperature)
end
test "returns true for non-empty string values" do
assert CallsignView.has_weather_field?(%{temperature: "72.5"}, :temperature)
end
test "returns false for empty string" do
refute CallsignView.has_weather_field?(%{temperature: ""}, :temperature)
end
end
describe "get_weather_field_zero/2" do
test "replaces N/A with 0" do
assert CallsignView.get_weather_field_zero(%{}, :temperature) == "0"
end
test "passes numeric values through" do
assert CallsignView.get_weather_field_zero(%{temperature: 72.5}, :temperature) == 72.5
end
end
describe "format_weather_value/3" do
test "returns nil for missing values" do
assert CallsignView.format_weather_value(%{}, :temperature, "en") == nil
end
test "formats numeric temperature with units" do
result = CallsignView.format_weather_value(%{temperature: 72.5}, :temperature, "en")
assert is_binary(result)
assert result =~ "72"
end
test "formats numeric wind_speed with a space separator" do
result = CallsignView.format_weather_value(%{wind_speed: 10.0}, :wind_speed, "en")
assert is_binary(result)
# Unit appears after the numeric value with a separator.
assert String.contains?(result, " ")
end
test "handles string numeric values" do
result = CallsignView.format_weather_value(%{temperature: "72.5"}, :temperature, "en")
assert is_binary(result)
end
test "handles string non-numeric values for untracked keys" do
# humidity has no entry in @weather_formatters, so binary values are
# returned as-is.
assert CallsignView.format_weather_value(%{humidity: "65"}, :humidity, "en") == "65"
end
test "returns nil for unparseable string values on tracked keys" do
assert CallsignView.format_weather_value(%{temperature: "not-a-number"}, :temperature, "en") ==
nil
end
test "returns stringified value for untracked numeric keys" do
# humidity is numeric but not in the formatter map — passes through as string.
assert CallsignView.format_weather_value(%{humidity: 65}, :humidity, "en") == "65"
end
test "formats rain fields with units" do
result = CallsignView.format_weather_value(%{rain_1h: 0.25}, :rain_1h, "en")
assert is_binary(result)
assert String.contains?(result, " ")
end
end
describe "live packet broadcast handling" do
test "ignores non-matching postgres_packet broadcasts", %{conn: conn} do
{:ok, lv, _html} = live(conn, ~p"/weather/OWNCALL", on_error: :warn)
# Broadcast an unrelated packet with no weather data
unrelated = %{
sender: "DIFFERENT",
temperature: nil,
humidity: nil,
pressure: nil,
wind_speed: nil,
wind_direction: nil,
rain_1h: nil
}
send(lv.pid, {:postgres_packet, unrelated})
Process.sleep(20)
assert Process.alive?(lv.pid)
end
test "ignores postgres_packet with wrong callsign", %{conn: conn} do
{:ok, lv, _html} = live(conn, ~p"/weather/MYCALL", on_error: :warn)
wrong_call = %{
sender: "OTHER",
temperature: 72.5,
humidity: 50,
pressure: nil,
wind_speed: nil,
wind_direction: nil,
rain_1h: nil
}
send(lv.pid, {:postgres_packet, wrong_call})
Process.sleep(20)
assert Process.alive?(lv.pid)
end
test "ignores unknown messages without crashing", %{conn: conn} do
{:ok, lv, _html} = live(conn, ~p"/weather/UNKCALL", on_error: :warn)
send(lv.pid, :some_unknown_message)
Process.sleep(20)
assert Process.alive?(lv.pid)
end
end
end