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