add entry/exit pages panel to analytics dashboard
All checks were successful
deploy / deploy (push) Successful in 1m28s

ROW_NUMBER() window function picks first/last pageview per session.
Both tables live in the pages tab and support the pathname filter.
6 new tests, 1061 total.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-23 21:14:24 +00:00
parent 162a5bfe9a
commit 9b78793701
3 changed files with 161 additions and 0 deletions

View File

@@ -287,6 +287,85 @@ defmodule Berrypod.AnalyticsTest do
end
end
describe "entry_pages/2" do
test "returns the first page per session" do
s1 = :crypto.strong_rand_bytes(8)
s2 = :crypto.strong_rand_bytes(8)
now = DateTime.utc_now() |> DateTime.truncate(:second)
earlier = DateTime.add(now, -60, :second)
insert_event(%{session_hash: s1, pathname: "/", inserted_at: earlier})
insert_event(%{session_hash: s1, pathname: "/about", inserted_at: now})
insert_event(%{session_hash: s2, pathname: "/products", inserted_at: earlier})
pages = Analytics.entry_pages(today_range())
pathnames = Enum.map(pages, & &1.pathname)
assert "/" in pathnames
assert "/products" in pathnames
refute "/about" in pathnames
end
test "counts sessions per entry page" do
s1 = :crypto.strong_rand_bytes(8)
s2 = :crypto.strong_rand_bytes(8)
s3 = :crypto.strong_rand_bytes(8)
now = DateTime.utc_now() |> DateTime.truncate(:second)
insert_event(%{session_hash: s1, pathname: "/"})
insert_event(%{session_hash: s2, pathname: "/"})
insert_event(%{session_hash: s3, pathname: "/about", inserted_at: now})
pages = Analytics.entry_pages(today_range())
home = Enum.find(pages, &(&1.pathname == "/"))
assert home.sessions == 2
end
test "returns empty list with no data" do
assert Analytics.entry_pages(today_range()) == []
end
end
describe "exit_pages/2" do
test "returns the last page per session" do
s1 = :crypto.strong_rand_bytes(8)
s2 = :crypto.strong_rand_bytes(8)
now = DateTime.utc_now() |> DateTime.truncate(:second)
earlier = DateTime.add(now, -60, :second)
insert_event(%{session_hash: s1, pathname: "/", inserted_at: earlier})
insert_event(%{session_hash: s1, pathname: "/about", inserted_at: now})
insert_event(%{session_hash: s2, pathname: "/products", inserted_at: earlier})
pages = Analytics.exit_pages(today_range())
pathnames = Enum.map(pages, & &1.pathname)
assert "/about" in pathnames
assert "/products" in pathnames
refute "/" in pathnames
end
test "counts sessions per exit page" do
s1 = :crypto.strong_rand_bytes(8)
s2 = :crypto.strong_rand_bytes(8)
now = DateTime.utc_now() |> DateTime.truncate(:second)
earlier = DateTime.add(now, -60, :second)
insert_event(%{session_hash: s1, pathname: "/", inserted_at: earlier})
insert_event(%{session_hash: s1, pathname: "/about", inserted_at: now})
insert_event(%{session_hash: s2, pathname: "/", inserted_at: earlier})
insert_event(%{session_hash: s2, pathname: "/about", inserted_at: now})
pages = Analytics.exit_pages(today_range())
about = Enum.find(pages, &(&1.pathname == "/about"))
assert about.sessions == 2
end
test "returns empty list with no data" do
assert Analytics.exit_pages(today_range()) == []
end
end
describe "delete_events_before/1" do
test "deletes old events" do
old = DateTime.add(DateTime.utc_now(), -400, :day) |> DateTime.truncate(:second)