- PageController: cover the legacy `/qsos` → `/contacts` redirect pair
(both the index and the id-preserving per-resource redirect), which
had no coverage since the route rename.
- Scorer property tests:
- f_to_c / c_to_f are inverses up to float epsilon, both propagate
nil, and the C→F slope is exactly 5/9.
- wind_speed_kts is non-negative, propagates nil on either axis,
and matches sqrt(u²+v²)·1.94384 (the 5-digit kts factor the
scorer uses).
- precip_to_rate_mmhr is non-negative, 0 for nil/zero/negative.
- dbz_to_rain_rate_mmhr is 0 below 5 dBZ (and for nil), and
monotonically non-decreasing above — guards against accidental
inversion of the Marshall-Palmer lookup.
Suite: 2,382 tests + 155 properties (was 2,380 + 148); coverage
71.08% → 71.12%; credo strict clean.
90 lines
3.3 KiB
Elixir
90 lines
3.3 KiB
Elixir
defmodule MicrowavepropWeb.PageControllerTest do
|
|
use MicrowavepropWeb.ConnCase
|
|
|
|
test "GET / redirects to /map", %{conn: conn} do
|
|
conn = get(conn, ~p"/")
|
|
assert redirected_to(conn) == "/map"
|
|
end
|
|
|
|
describe "legacy /qsos redirects" do
|
|
# The app was renamed `qsos` → `contacts` in the 2025 refactor; the
|
|
# old routes stay around so bookmarked links don't 404.
|
|
test "GET /qsos permanent-redirects to /contacts", %{conn: conn} do
|
|
conn = get(conn, "/qsos")
|
|
assert redirected_to(conn) == "/contacts"
|
|
end
|
|
|
|
test "GET /qsos/:id permanent-redirects to /contacts/:id preserving the id", %{conn: conn} do
|
|
id = "7d3cf5c8-6fd4-44b5-9b8e-84d9ef2c1b10"
|
|
conn = get(conn, "/qsos/#{id}")
|
|
assert redirected_to(conn) == "/contacts/#{id}"
|
|
end
|
|
end
|
|
|
|
# RFC 8288 Link headers for agent discovery. These advertise resources
|
|
# that actually exist in this app to crawlers/agents that look at
|
|
# response headers before parsing HTML.
|
|
describe "Link headers (RFC 8288)" do
|
|
test "homepage response carries Link headers", %{conn: conn} do
|
|
conn = get(conn, ~p"/")
|
|
[link] = get_resp_header(conn, "link")
|
|
|
|
assert link =~ ~s(</algo>; rel="service-doc")
|
|
assert link =~ ~s(</about>; rel="about")
|
|
assert link =~ ~s(</privacy>; rel="privacy-policy")
|
|
assert link =~ ~s(</sitemap.xml>; rel="sitemap")
|
|
end
|
|
|
|
test "browser-pipeline pages carry the same Link headers", %{conn: conn} do
|
|
conn = get(conn, ~p"/about")
|
|
[link] = get_resp_header(conn, "link")
|
|
assert link =~ ~s(rel="service-doc")
|
|
assert link =~ ~s(rel="about")
|
|
end
|
|
end
|
|
|
|
# Markdown for Agents: content negotiation so agents that send
|
|
# `Accept: text/markdown` get a real markdown document instead of a 406.
|
|
# We only serve markdown for paths where we actually have markdown source
|
|
# (the homepage summary and /algo). Other paths still 406 rather than lie
|
|
# with a converted-on-the-fly body.
|
|
describe "Markdown for Agents" do
|
|
test "GET / with Accept: text/markdown returns a markdown document", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("accept", "text/markdown")
|
|
|> get(~p"/")
|
|
|
|
assert conn.status == 200
|
|
assert ["text/markdown; charset=utf-8"] = get_resp_header(conn, "content-type")
|
|
[tokens] = get_resp_header(conn, "x-markdown-tokens")
|
|
assert String.to_integer(tokens) > 0
|
|
assert conn.resp_body =~ "# "
|
|
end
|
|
|
|
test "GET /algo with Accept: text/markdown returns algo.md", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("accept", "text/markdown")
|
|
|> get(~p"/algo")
|
|
|
|
assert conn.status == 200
|
|
assert ["text/markdown; charset=utf-8"] = get_resp_header(conn, "content-type")
|
|
assert conn.resp_body =~ "Microwave Propagation Algorithm"
|
|
end
|
|
|
|
test "GET / without markdown Accept still redirects to /map", %{conn: conn} do
|
|
conn = get(conn, ~p"/")
|
|
assert redirected_to(conn) == "/map"
|
|
end
|
|
|
|
test "Accept lists with both html and markdown prefer markdown when specified", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("accept", "text/markdown, text/html;q=0.9")
|
|
|> get(~p"/")
|
|
|
|
assert ["text/markdown; charset=utf-8"] = get_resp_header(conn, "content-type")
|
|
end
|
|
end
|
|
end
|