All checks were successful
deploy / deploy (push) Successful in 1m19s
Click any row in pages, sources, countries, or devices tables to filter the entire dashboard by that dimension. Active filters show as dismissible chips. Filters thread through all queries including previous-period deltas. 1050 tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
165 lines
5.0 KiB
Elixir
165 lines
5.0 KiB
Elixir
defmodule BerrypodWeb.Admin.AnalyticsTest do
|
|
use BerrypodWeb.ConnCase, async: false
|
|
|
|
import Phoenix.LiveViewTest
|
|
import Berrypod.AccountsFixtures
|
|
|
|
alias Berrypod.Analytics.{Buffer, Event}
|
|
alias Berrypod.Repo
|
|
|
|
setup do
|
|
send(Buffer, :flush)
|
|
:timer.sleep(50)
|
|
|
|
user = user_fixture()
|
|
%{user: user}
|
|
end
|
|
|
|
describe "unauthenticated" do
|
|
test "redirects to login", %{conn: conn} do
|
|
{:error, redirect} = live(conn, ~p"/admin/analytics")
|
|
assert {:redirect, %{to: path}} = redirect
|
|
assert path == ~p"/users/log-in"
|
|
end
|
|
end
|
|
|
|
describe "analytics dashboard" do
|
|
setup %{conn: conn, user: user} do
|
|
%{conn: log_in_user(conn, user)}
|
|
end
|
|
|
|
test "renders the analytics page", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/analytics")
|
|
|
|
assert html =~ "Analytics"
|
|
assert html =~ "Unique visitors"
|
|
assert html =~ "Total pageviews"
|
|
assert html =~ "Bounce rate"
|
|
assert html =~ "Visit duration"
|
|
end
|
|
|
|
test "shows zero state with no data", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/analytics")
|
|
|
|
assert html =~ "No data for this period"
|
|
end
|
|
|
|
test "shows data when events exist", %{conn: conn} do
|
|
now = DateTime.utc_now() |> DateTime.truncate(:second)
|
|
|
|
Repo.insert_all(Event, [
|
|
[
|
|
id: Ecto.UUID.generate(),
|
|
name: "pageview",
|
|
pathname: "/",
|
|
visitor_hash: :crypto.strong_rand_bytes(8),
|
|
session_hash: :crypto.strong_rand_bytes(8),
|
|
browser: "Chrome",
|
|
os: "macOS",
|
|
inserted_at: now
|
|
]
|
|
])
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
assert has_element?(view, "[data-bars]")
|
|
end
|
|
|
|
test "changes period", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
html = render_click(view, "change_period", %{"period" => "7d"})
|
|
assert html =~ "Analytics"
|
|
end
|
|
|
|
test "changes tab to sources", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
html = render_click(view, "change_tab", %{"tab" => "sources"})
|
|
assert html =~ "Top sources"
|
|
assert html =~ "Top referrers"
|
|
end
|
|
|
|
test "changes tab to countries", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
html = render_click(view, "change_tab", %{"tab" => "countries"})
|
|
assert html =~ "Countries"
|
|
end
|
|
|
|
test "changes tab to devices", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
html = render_click(view, "change_tab", %{"tab" => "devices"})
|
|
assert html =~ "Browsers"
|
|
assert html =~ "Operating systems"
|
|
assert html =~ "Screen sizes"
|
|
end
|
|
|
|
test "changes tab to funnel", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
html = render_click(view, "change_tab", %{"tab" => "funnel"})
|
|
assert html =~ "Conversion funnel"
|
|
end
|
|
|
|
test "clicking a source adds a filter chip", %{conn: conn} do
|
|
now = DateTime.utc_now() |> DateTime.truncate(:second)
|
|
|
|
Repo.insert_all(Event, [
|
|
[
|
|
id: Ecto.UUID.generate(),
|
|
name: "pageview",
|
|
pathname: "/",
|
|
visitor_hash: :crypto.strong_rand_bytes(8),
|
|
session_hash: :crypto.strong_rand_bytes(8),
|
|
referrer_source: "Google",
|
|
inserted_at: now
|
|
]
|
|
])
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
# Switch to sources tab and click the source
|
|
render_click(view, "change_tab", %{"tab" => "sources"})
|
|
|
|
html =
|
|
render_click(view, "add_filter", %{"dimension" => "referrer_source", "value" => "Google"})
|
|
|
|
assert html =~ "Source: Google"
|
|
assert has_element?(view, "#analytics-filters")
|
|
end
|
|
|
|
test "removing a filter chip clears it", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
render_click(view, "add_filter", %{"dimension" => "country_code", "value" => "GB"})
|
|
assert render(view) =~ "Country: United Kingdom"
|
|
|
|
html = render_click(view, "remove_filter", %{"dimension" => "country_code"})
|
|
refute html =~ "Country: United Kingdom"
|
|
end
|
|
|
|
test "clear all removes all filters", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
render_click(view, "add_filter", %{"dimension" => "country_code", "value" => "GB"})
|
|
render_click(view, "add_filter", %{"dimension" => "browser", "value" => "Chrome"})
|
|
assert render(view) =~ "Clear all"
|
|
|
|
html = render_click(view, "clear_filters", %{})
|
|
refute html =~ "Country: United Kingdom"
|
|
refute html =~ "Browser: Chrome"
|
|
end
|
|
|
|
test "changing period preserves filters", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/analytics")
|
|
|
|
render_click(view, "add_filter", %{"dimension" => "country_code", "value" => "GB"})
|
|
html = render_click(view, "change_period", %{"period" => "7d"})
|
|
|
|
assert html =~ "Country: United Kingdom"
|
|
end
|
|
end
|
|
end
|