test: cover radio/edit_notifier
13 characterization tests for deliver_edit_approved + deliver_edit_rejected: to/from/reply-to, subject format, callsign greeting, APPROVED/REJECTED tags, band formatting (MHz vs GHz), change rendering, admin-note present/nil/empty, endpoint URL link, preload tolerance.
This commit is contained in:
parent
58e6fcff0d
commit
4f956e4606
1 changed files with 241 additions and 0 deletions
241
test/microwaveprop/radio/edit_notifier_test.exs
Normal file
241
test/microwaveprop/radio/edit_notifier_test.exs
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
defmodule Microwaveprop.Radio.EditNotifierTest do
|
||||
@moduledoc """
|
||||
Characterization tests for the edit-review email notifier.
|
||||
|
||||
These pin down the current behavior of `deliver_edit_approved/1` and
|
||||
`deliver_edit_rejected/1` so future refactors get a compile-in safety net.
|
||||
"""
|
||||
use Microwaveprop.DataCase, async: true
|
||||
|
||||
import Swoosh.TestAssertions
|
||||
|
||||
alias Microwaveprop.Accounts
|
||||
alias Microwaveprop.Radio.Contact
|
||||
alias Microwaveprop.Radio.ContactEdit
|
||||
alias Microwaveprop.Radio.EditNotifier
|
||||
|
||||
@contact_attrs %{
|
||||
station1: "W5ISP",
|
||||
station2: "K5TR",
|
||||
qso_timestamp: ~U[2026-04-01 14:30:00Z],
|
||||
grid1: "EM13",
|
||||
grid2: "EL29",
|
||||
pos1: %{"lat" => 33.5, "lon" => -97.0},
|
||||
pos2: %{"lat" => 29.5, "lon" => -98.5},
|
||||
mode: "CW",
|
||||
band: Decimal.new("10000"),
|
||||
distance_km: Decimal.new("450")
|
||||
}
|
||||
|
||||
@user_attrs %{
|
||||
callsign: "W5TEST",
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
password: "testpassword123"
|
||||
}
|
||||
|
||||
defp insert_contact(attrs \\ %{}) do
|
||||
{:ok, contact} =
|
||||
%Contact{}
|
||||
|> Contact.changeset(Map.merge(@contact_attrs, attrs))
|
||||
|> Repo.insert()
|
||||
|
||||
contact
|
||||
end
|
||||
|
||||
defp insert_user(attrs \\ %{}) do
|
||||
{:ok, user} = Accounts.register_user(Map.merge(@user_attrs, attrs))
|
||||
user
|
||||
end
|
||||
|
||||
defp insert_edit(contact, user, attrs \\ %{}) do
|
||||
defaults = %{
|
||||
contact_id: contact.id,
|
||||
user_id: user.id,
|
||||
proposed_changes: %{"grid1" => "EM13kk"}
|
||||
}
|
||||
|
||||
{:ok, edit} =
|
||||
%ContactEdit{}
|
||||
|> ContactEdit.changeset(Map.merge(defaults, attrs))
|
||||
|> Repo.insert()
|
||||
|
||||
# apply anything the review_changeset path wouldn't (admin_note, etc.)
|
||||
extras =
|
||||
attrs
|
||||
|> Map.drop([:contact_id, :user_id, :proposed_changes])
|
||||
|> Map.to_list()
|
||||
|
||||
if extras == [] do
|
||||
edit
|
||||
else
|
||||
edit |> Ecto.Changeset.change(extras) |> Repo.update!()
|
||||
end
|
||||
end
|
||||
|
||||
describe "deliver_edit_approved/1" do
|
||||
test "sends a single email to the submitter from the configured defaults" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user, %{admin_note: "Looks right, thanks"})
|
||||
|
||||
assert {:ok, %Swoosh.Email{}} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert_email_sent(fn email ->
|
||||
assert email.to == [{"", "test@example.com"}]
|
||||
assert email.from == {"NTMS Propagation", "prop@w5isp.com"}
|
||||
assert email.reply_to == {"", "graham@mcintire.me"}
|
||||
assert email.subject == "Your contact edit was approved"
|
||||
end)
|
||||
end
|
||||
|
||||
test "body addresses the submitter by callsign and names APPROVED" do
|
||||
contact = insert_contact()
|
||||
user = insert_user(%{callsign: "K5ABC", email: "k5abc@example.com"})
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert email.text_body =~ "Hi K5ABC,"
|
||||
assert email.text_body =~ "APPROVED"
|
||||
refute email.text_body =~ "REJECTED"
|
||||
end
|
||||
|
||||
test "body lists the contact endpoints, band, and qso_timestamp" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert email.text_body =~ "W5ISP <-> K5TR"
|
||||
assert email.text_body =~ "10 GHz"
|
||||
assert email.text_body =~ "2026-04-01 14:30 UTC"
|
||||
end
|
||||
|
||||
test "formats sub-GHz bands in MHz" do
|
||||
contact = insert_contact(%{band: Decimal.new("432")})
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert email.text_body =~ "432 MHz"
|
||||
refute email.text_body =~ "GHz"
|
||||
end
|
||||
|
||||
test "body lists each proposed change on its own line" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
|
||||
edit =
|
||||
insert_edit(contact, user, %{
|
||||
proposed_changes: %{"grid1" => "EM13kk", "mode" => "SSB"}
|
||||
})
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert email.text_body =~ " - grid1: EM13kk"
|
||||
assert email.text_body =~ " - mode: SSB"
|
||||
end
|
||||
|
||||
test "includes an admin note when present" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user, %{admin_note: "Verified against QRZ"})
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert email.text_body =~ "Admin note: Verified against QRZ"
|
||||
end
|
||||
|
||||
test "omits the admin-note line when note is nil" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user, %{admin_note: nil})
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
refute email.text_body =~ "Admin note:"
|
||||
end
|
||||
|
||||
test "omits the admin-note line when note is empty string" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user, %{admin_note: ""})
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
refute email.text_body =~ "Admin note:"
|
||||
end
|
||||
|
||||
test "includes a contact view link built from the endpoint url" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_approved(edit)
|
||||
|
||||
assert email.text_body =~ "#{MicrowavepropWeb.Endpoint.url()}/contacts/#{contact.id}"
|
||||
end
|
||||
|
||||
test "preloads associations if the caller passes a bare record" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
# Pass the schema back after re-fetch without preloads — the notifier
|
||||
# must tolerate that and still resolve user.callsign / contact.station1.
|
||||
bare = Repo.get!(ContactEdit, edit.id)
|
||||
|
||||
assert {:ok, email} = EditNotifier.deliver_edit_approved(bare)
|
||||
assert email.text_body =~ "Hi W5TEST,"
|
||||
assert email.text_body =~ "W5ISP <-> K5TR"
|
||||
end
|
||||
end
|
||||
|
||||
describe "deliver_edit_rejected/1" do
|
||||
test "sends an email with the rejected subject to the submitter" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
assert {:ok, %Swoosh.Email{}} = EditNotifier.deliver_edit_rejected(edit)
|
||||
|
||||
assert_email_sent(fn email ->
|
||||
assert email.to == [{"", "test@example.com"}]
|
||||
assert email.from == {"NTMS Propagation", "prop@w5isp.com"}
|
||||
assert email.reply_to == {"", "graham@mcintire.me"}
|
||||
assert email.subject == "Your contact edit was rejected"
|
||||
end)
|
||||
end
|
||||
|
||||
test "body says REJECTED and labels the changes as 'Proposed changes:'" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
|
||||
edit =
|
||||
insert_edit(contact, user, %{
|
||||
proposed_changes: %{"station2" => "W5XYZ"},
|
||||
admin_note: "Mismatch with log"
|
||||
})
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_rejected(edit)
|
||||
|
||||
assert email.text_body =~ "REJECTED"
|
||||
refute email.text_body =~ "APPROVED"
|
||||
assert email.text_body =~ "Proposed changes:\n - station2: W5XYZ"
|
||||
assert email.text_body =~ "Admin note: Mismatch with log"
|
||||
end
|
||||
|
||||
test "includes the contact view link for rejected edits too" do
|
||||
contact = insert_contact()
|
||||
user = insert_user()
|
||||
edit = insert_edit(contact, user)
|
||||
|
||||
{:ok, email} = EditNotifier.deliver_edit_rejected(edit)
|
||||
|
||||
assert email.text_body =~ "#{MicrowavepropWeb.Endpoint.url()}/contacts/#{contact.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue