Coverage:
- Adds focused tests across 13 files covering previously-uncovered
branches: Packet changeset normalisation (course, wind_direction,
struct data_extended); Packets store_packet edge cases (nested
position shapes, ssid handling, string-keyed raw_packet);
DeviceIdentification HTTP success/404 via Req plug stub; ResendAdapter
catch-all body, deliver_many, nil/binary formatters; ApiDocsLive
packets with missing fields; AprsSymbol normalize helpers;
BadPacketsLive refresh and postgres_notify; MobileChannel handle_info
catch-all and postgres_packet path; PacketProcessor existing-marker
movement detection; PacketReplay sanitize_value type clauses;
InsertOptimizer GenServer lifecycle and negative-duration metric;
PageController shutdown-handler integration; UrlParams delegated
helpers.
- mix.exs: configure test_coverage with summary threshold of 87 and
ignore_modules for test fixtures and macro-only template modules.
Bug fix:
- MapLive.Index handle_info: add a clause for the raw {:new_deployment,
_} tuple. Phoenix.PubSub.broadcast delivers the raw payload to plain
subscribers, but the existing handler only matched the %Broadcast{}
fast-lane wrapper. DeploymentNotifier broadcasts via the raw path,
which crashed the LiveView under test concurrency.
Submodule:
- Update .gitmodules vendor/aprs URL from
https://github.com/aprsme/aprs.git to
ssh://git@codeberg.org/gmcintire/aprs.git.
180 lines
5.5 KiB
Elixir
180 lines
5.5 KiB
Elixir
defmodule AprsmeWeb.ApiDocsLiveTest do
|
|
use AprsmeWeb.ConnCase
|
|
|
|
import Aprsme.PacketsFixtures
|
|
import Phoenix.LiveViewTest
|
|
|
|
describe "ApiDocsLive" do
|
|
test "renders the API documentation page", %{conn: conn} do
|
|
{:ok, _lv, html} = live(conn, ~p"/api", on_error: :warn)
|
|
assert html =~ "API Documentation"
|
|
assert html =~ "/api/v1/callsign"
|
|
assert html =~ "/api/v1/weather/nearby"
|
|
end
|
|
|
|
test "update_callsign event updates the callsign input", %{conn: conn} do
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
rendered =
|
|
lv
|
|
|> element("#test_callsign")
|
|
|> render_change(%{"callsign" => "k1abc"})
|
|
|
|
assert rendered =~ "k1abc"
|
|
end
|
|
|
|
test "submitting test_api with empty callsign shows an error", %{conn: conn} do
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
rendered =
|
|
lv
|
|
|> form("form[phx-submit=\"test_api\"]", %{"callsign" => " "})
|
|
|> render_submit()
|
|
|
|
assert rendered =~ "Please enter a callsign"
|
|
end
|
|
|
|
test "invalid callsign format returns an error response", %{conn: conn} do
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
# Seed the callsign via the phx-change so the form submits properly.
|
|
lv
|
|
|> element("#test_callsign")
|
|
|> render_change(%{"callsign" => "BAD!"})
|
|
|
|
rendered =
|
|
lv
|
|
|> form("form[phx-submit=\"test_api\"]", %{"callsign" => "BAD!"})
|
|
|> render_submit()
|
|
|
|
# The handler sends itself a :call_api message; after it returns the
|
|
# result assign should contain the invalid-format error JSON.
|
|
render(lv)
|
|
assert rendered =~ "Test API" or rendered =~ "Testing..."
|
|
|
|
# Wait for the async message handler to complete.
|
|
:ok = Process.sleep(50)
|
|
assert render(lv) =~ "Invalid callsign format"
|
|
end
|
|
|
|
test "valid callsign with no packets returns 'No packets found'", %{conn: conn} do
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
lv
|
|
|> element("#test_callsign")
|
|
|> render_change(%{"callsign" => "N0CALL-9"})
|
|
|
|
lv
|
|
|> form("form[phx-submit=\"test_api\"]", %{"callsign" => "N0CALL-9"})
|
|
|> render_submit()
|
|
|
|
# Let the async :call_api message run.
|
|
:ok = Process.sleep(100)
|
|
rendered = render(lv)
|
|
# Either "No packets found" (most common in a clean test DB) or a
|
|
# packet result. Both exercise the happy path of make_http_request.
|
|
assert rendered =~ "No packets found" or rendered =~ "data"
|
|
end
|
|
|
|
test "valid callsign with existing packet returns JSON data", %{conn: conn} do
|
|
# Create a packet in the DB so the test_api event actually returns data.
|
|
_packet =
|
|
packet_fixture(%{
|
|
sender: "K5ABC-9",
|
|
base_callsign: "K5ABC",
|
|
ssid: "9",
|
|
received_at: DateTime.utc_now(),
|
|
lat: Decimal.new("33.0"),
|
|
lon: Decimal.new("-96.5"),
|
|
has_position: true,
|
|
comment: "API test packet",
|
|
temperature: 72.5,
|
|
humidity: 50
|
|
})
|
|
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
lv
|
|
|> element("#test_callsign")
|
|
|> render_change(%{"callsign" => "K5ABC-9"})
|
|
|
|
lv
|
|
|> form("form[phx-submit=\"test_api\"]", %{"callsign" => "K5ABC-9"})
|
|
|> render_submit()
|
|
|
|
:ok = Process.sleep(150)
|
|
rendered = render(lv)
|
|
assert rendered =~ "K5ABC"
|
|
assert rendered =~ "data"
|
|
end
|
|
|
|
test "packet with no ssid renders without ssid suffix", %{conn: conn} do
|
|
# Exercises format_callsign(base, nil) and format_callsign(base, "0").
|
|
# Also exercises format_position(%{has_position: false}) and
|
|
# format_symbol(%{symbol_code: nil, symbol_table_id: nil}).
|
|
_packet =
|
|
packet_fixture(%{
|
|
sender: "W1AW",
|
|
base_callsign: "W1AW",
|
|
ssid: "0",
|
|
received_at: DateTime.utc_now(),
|
|
lat: nil,
|
|
lon: nil,
|
|
has_position: false,
|
|
symbol_code: nil,
|
|
symbol_table_id: nil,
|
|
device_identifier: nil
|
|
})
|
|
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
lv
|
|
|> element("#test_callsign")
|
|
|> render_change(%{"callsign" => "W1AW"})
|
|
|
|
lv
|
|
|> form("form[phx-submit=\"test_api\"]", %{"callsign" => "W1AW"})
|
|
|> render_submit()
|
|
|
|
:ok = Process.sleep(150)
|
|
rendered = render(lv)
|
|
# Base callsign without -ssid suffix must appear; format_callsign("W1AW", "0")
|
|
# collapses to "W1AW".
|
|
assert rendered =~ "W1AW"
|
|
# No position fields when has_position is false.
|
|
refute rendered =~ "\"latitude\""
|
|
end
|
|
|
|
test "packet with message fields renders message block", %{conn: conn} do
|
|
# Exercises format_message(packet) when at least one message field is set.
|
|
_packet =
|
|
packet_fixture(%{
|
|
sender: "K9MSG-1",
|
|
base_callsign: "K9MSG",
|
|
ssid: "1",
|
|
received_at: DateTime.utc_now(),
|
|
lat: Decimal.new("33.0"),
|
|
lon: Decimal.new("-96.5"),
|
|
has_position: true,
|
|
addressee: "DEST",
|
|
message_text: "Hello",
|
|
message_number: "001"
|
|
})
|
|
|
|
{:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)
|
|
|
|
lv
|
|
|> element("#test_callsign")
|
|
|> render_change(%{"callsign" => "K9MSG-1"})
|
|
|
|
lv
|
|
|> form("form[phx-submit=\"test_api\"]", %{"callsign" => "K9MSG-1"})
|
|
|> render_submit()
|
|
|
|
:ok = Process.sleep(150)
|
|
rendered = render(lv)
|
|
assert rendered =~ "K9MSG"
|
|
assert rendered =~ "Hello"
|
|
end
|
|
end
|
|
end
|