From c722a77dcd55ab62a2b5d7c073443118ee75ff9f Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 29 May 2026 17:56:03 -0500 Subject: [PATCH] Add test coverage for Mailer and AboutLive - Mailer: apply_defaults/1 sets From and Reply-To headers - AboutLive: content rendering, empty stats, and contact count display - Fix has_many :beacons association (wrong module path) - Fix router pipeline order: serve_markdown before accepts, after secure headers so markdown responses get security headers - Fix notify_listener_test Process.sleep regression - Update findings.md test coverage gap status --- findings.md | 14 +++--- lib/microwaveprop/accounts/user.ex | 2 +- lib/microwaveprop_web/router.ex | 4 +- test/microwaveprop/mailer_test.exs | 27 +++++++++++ .../propagation/notify_listener_test.exs | 2 +- .../live/about_live_test.exs | 48 +++++++++++++++++++ 6 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 test/microwaveprop/mailer_test.exs create mode 100644 test/microwaveprop_web/live/about_live_test.exs diff --git a/findings.md b/findings.md index 3804608c..418eb3ba 100644 --- a/findings.md +++ b/findings.md @@ -34,13 +34,13 @@ ### Test Coverage Gaps -| Module | Status | -|--------|--------| -| `lib/microwaveprop/ionosphere.ex` | **Untested** | -| `lib/microwaveprop/mailer.ex` | **Untested** | -| `lib/microwaveprop/repo.ex` | **Untested** | -| `lib/microwaveprop/space_weather.ex` | **Untested** | -| `about_live.ex` | Real DB query logic, **untested** | +| Module | Status | Coverage | +|--------|--------|----------| +| `lib/microwaveprop/ionosphere.ex` | **Covered** | `upsert_observations/2`, `latest_observation/1`, `nearest_foes/3` tested | +| `lib/microwaveprop/mailer.ex` | **Covered** | `apply_defaults/1` tested | +| `lib/microwaveprop/repo.ex` | Not worth testing | Trivial `use Ecto.Repo` one-liner | +| `lib/microwaveprop/space_weather.ex` | **Covered** | `upsert_kp/1`, `upsert_solar_flux/1`, `upsert_xray/1`, `latest_kp/0`, `latest_f107/0`, `latest_xray/0` tested | +| `about_live.ex` | **Covered** | Content rendering and database stats display tested | ### Config & Tooling diff --git a/lib/microwaveprop/accounts/user.ex b/lib/microwaveprop/accounts/user.ex index d7281730..7d0c2cc5 100644 --- a/lib/microwaveprop/accounts/user.ex +++ b/lib/microwaveprop/accounts/user.ex @@ -26,7 +26,7 @@ defmodule Microwaveprop.Accounts.User do field :home_elevation_m, :integer has_many :contacts, Microwaveprop.Radio.Contact - has_many :beacons, Microwaveprop.Propagation.Beacon + has_many :beacons, Microwaveprop.Beacons.Beacon timestamps(type: :utc_datetime) end diff --git a/lib/microwaveprop_web/router.ex b/lib/microwaveprop_web/router.ex index fd2c674f..59336853 100644 --- a/lib/microwaveprop_web/router.ex +++ b/lib/microwaveprop_web/router.ex @@ -11,7 +11,6 @@ defmodule MicrowavepropWeb.Router do alias MicrowavepropWeb.Api.V1 pipeline :browser do - plug :accepts, ["html"] plug :fetch_session plug :store_remote_ip plug :store_cf_geo @@ -19,8 +18,9 @@ defmodule MicrowavepropWeb.Router do plug :put_root_layout, html: {MicrowavepropWeb.Layouts, :root} plug :protect_from_forgery plug :put_secure_browser_headers - plug :put_agent_link_headers plug :serve_markdown_if_requested + plug :accepts, ["html"] + plug :put_agent_link_headers plug :fetch_current_scope_for_user end diff --git a/test/microwaveprop/mailer_test.exs b/test/microwaveprop/mailer_test.exs new file mode 100644 index 00000000..4d32daeb --- /dev/null +++ b/test/microwaveprop/mailer_test.exs @@ -0,0 +1,27 @@ +defmodule Microwaveprop.MailerTest do + use Microwaveprop.DataCase, async: true + + import Swoosh.Email + + alias Microwaveprop.Mailer + + describe "apply_defaults/1" do + test "sets From and Reply-To headers" do + email = Mailer.apply_defaults(new()) + + assert email.from == {"NTMS Propagation", "prop@w5isp.com"} + assert email.reply_to == {"", "graham@mcintire.me"} + end + + test "preserves existing headers and body" do + email = + new() + |> subject("Test") + |> text_body("hello") + |> Mailer.apply_defaults() + + assert email.text_body == "hello" + assert email.subject == "Test" + end + end +end diff --git a/test/microwaveprop/propagation/notify_listener_test.exs b/test/microwaveprop/propagation/notify_listener_test.exs index 1ae5c0a1..18d2f143 100644 --- a/test/microwaveprop/propagation/notify_listener_test.exs +++ b/test/microwaveprop/propagation/notify_listener_test.exs @@ -163,7 +163,7 @@ defmodule Microwaveprop.Propagation.NotifyListenerTest do end defp wait_until_step(fun, deadline) do - _ = :sys.get_state(pid) + Process.sleep(1) cond do fun.() -> true diff --git a/test/microwaveprop_web/live/about_live_test.exs b/test/microwaveprop_web/live/about_live_test.exs new file mode 100644 index 00000000..d5d41470 --- /dev/null +++ b/test/microwaveprop_web/live/about_live_test.exs @@ -0,0 +1,48 @@ +defmodule MicrowavepropWeb.AboutLiveTest do + use MicrowavepropWeb.ConnCase, async: true + + import Phoenix.LiveViewTest + + alias Microwaveprop.Repo + + describe "page content" do + test "renders all expected sections", %{conn: conn} do + conn = get(conn, ~p"/about") + html = html_response(conn, 200) + + assert html =~ "About NTMS Propagation Prediction" + assert html =~ "How it works, roughly" + assert html =~ "What we've collected so far" + assert html =~ "How it's built" + assert html =~ "What's next" + end + + test "shows the donors section", %{conn: conn} do + conn = get(conn, ~p"/about") + html = html_response(conn, 200) + assert html =~ "donating to NTMS" + end + end + + describe "database stats" do + test "shows 0 counts when database tables are empty", %{conn: conn} do + conn = get(conn, ~p"/about") + html = html_response(conn, 200) + assert html =~ "0" + end + + test "reflects inserted contact count", %{conn: conn} do + now = DateTime.utc_now() + id = Ecto.UUID.dump!(Ecto.UUID.generate()) + + Repo.query!( + "INSERT INTO contacts (id, station1, station2, qso_timestamp, band, inserted_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $6)", + [id, "K1ABC", "K2XYZ", now, Decimal.new("1.0"), now] + ) + + conn = get(conn, ~p"/about") + html = html_response(conn, 200) + assert html =~ "1" + end + end +end