Two fixes cover the blank "analysis breakdown" panel the user reported:
1. Bound the point_detail fallback lookback to 24h. Previously
factors_from_fallback_profile would happily use a week-old analysis
profile when no current one existed — now anything older than 24h
returns an empty factor map so the UI can surface "breakdown
unavailable" instead of silently misattributing.
2. Move the Plausible analytics snippet from Layouts.app into
root.html.heex. Full-bleed LiveViews (/map, /contacts/map,
/weather, home) bypass Layouts.app, so the snippet only loaded on
the navbar-wrapped pages. root.html.heex is loaded once per HTTP
document so coverage is now universal.
Added ~30 tests locking both down:
• point_detail fallback: exact-time wins, 24h boundary accepted,
30h-stale rejected, multi-band coverage, missing-cell degrades to
empty factors, default-valid_time path
• analytics_test.exs: Plausible script present on 12 representative
pages, exactly once, loaded async, surviving a login round-trip
Also fixed pre-existing credo issues per standing rule: shortened the
map_live_test ETS match_delete call, extracted a function from the
deeply-nested hrrr_point_enqueuer.enqueue_for_contacts/1 cond, and
swapped Mix.Tasks.Rust.Golden's IO.inspect for Mix.shell().info.
83 lines
3.4 KiB
Elixir
83 lines
3.4 KiB
Elixir
defmodule MicrowavepropWeb.AnalyticsTest do
|
||
@moduledoc """
|
||
Ensures the Plausible analytics snippet is present on every page the
|
||
app serves. Plausible lives in `root.html.heex` (loaded by every
|
||
request through the root layout) precisely so /map, /weather, and the
|
||
other full-bleed live views that bypass `<Layouts.app>` still load
|
||
the tracker. These tests lock that behaviour in so a future refactor
|
||
that moves the snippet back into `Layouts.app` can't silently drop
|
||
analytics on the three highest-traffic pages.
|
||
"""
|
||
use MicrowavepropWeb.ConnCase, async: true
|
||
|
||
@plausible_script_url "https://a.w5isp.com/js/pa-3eKACFxtbw6MHrTDA28wG.js"
|
||
|
||
# Pages in this list are fetched through the router and their rendered
|
||
# HTML asserted to contain the Plausible snippet. Any HTML route that
|
||
# a human-visible page lives behind belongs here.
|
||
@pages_to_check [
|
||
{"/map", "propagation map"},
|
||
{"/contacts/map", "contact map"},
|
||
{"/weather", "weather map"},
|
||
{"/about", "about page"},
|
||
{"/algo", "algorithm docs"},
|
||
{"/privacy", "privacy policy"},
|
||
{"/submit", "QSO submission form"},
|
||
{"/contacts", "contact list"},
|
||
{"/path", "path analysis"},
|
||
{"/beacons", "beacon list"},
|
||
{"/users/register", "registration form"},
|
||
{"/users/log-in", "login form"}
|
||
]
|
||
|
||
for {path, label} <- @pages_to_check do
|
||
test "#{label} (#{path}) includes the Plausible script tag", %{conn: conn} do
|
||
html = conn |> get(unquote(path)) |> html_response(200)
|
||
|
||
assert html =~ unquote(@plausible_script_url),
|
||
"Plausible script missing on #{unquote(path)} — check root.html.heex"
|
||
end
|
||
|
||
test "#{label} (#{path}) wires up window.plausible() via plausible.init", %{conn: conn} do
|
||
html = conn |> get(unquote(path)) |> html_response(200)
|
||
|
||
assert html =~ "window.plausible",
|
||
"Plausible init stub missing on #{unquote(path)}"
|
||
|
||
assert html =~ "plausible.init",
|
||
"plausible.init() call missing on #{unquote(path)}"
|
||
end
|
||
end
|
||
|
||
test "the script tag is emitted exactly once per page (no duplicates)", %{conn: conn} do
|
||
# If the snippet accidentally returns to both `root.html.heex` AND
|
||
# `Layouts.app`, pages that use `<Layouts.app>` would load the tag
|
||
# twice and double-count pageviews. Assert a single occurrence on a
|
||
# layout-wrapped page.
|
||
html = conn |> get(~p"/about") |> html_response(200)
|
||
occurrences = html |> String.split(@plausible_script_url) |> length()
|
||
# String.split + length: N occurrences → N+1 pieces. One occurrence
|
||
# is the expected state.
|
||
assert occurrences == 2,
|
||
"Plausible script appears #{occurrences - 1}×; expected 1 on /about"
|
||
end
|
||
|
||
test "the script loads asynchronously so it can't block the first paint", %{conn: conn} do
|
||
html = conn |> get(~p"/about") |> html_response(200)
|
||
|
||
assert html =~ ~r/<script\s+async\s+src="#{Regex.escape(@plausible_script_url)}"/,
|
||
"Plausible script must be loaded with `async` to avoid blocking first paint"
|
||
end
|
||
|
||
test "registered-user pages still carry the snippet after login", %{conn: conn} do
|
||
user =
|
||
Microwaveprop.AccountsFixtures.user_fixture(%{
|
||
password: "hunter2 hunter2 hunter2",
|
||
password_confirmation: "hunter2 hunter2 hunter2"
|
||
})
|
||
|
||
conn = log_in_user(conn, user)
|
||
html = conn |> get(~p"/users/settings") |> html_response(200)
|
||
assert html =~ @plausible_script_url
|
||
end
|
||
end
|