analytics/test/plausible/goals_test.exs

244 lines
7.9 KiB
Elixir

defmodule Plausible.GoalsTest do
use Plausible.DataCase
use Plausible
alias Plausible.Goals
test "create/2 creates goals and trims input" do
site = insert(:site)
{:ok, goal} = Goals.create(site, %{"page_path" => "/foo bar "})
assert goal.page_path == "/foo bar"
{:ok, goal} = Goals.create(site, %{"event_name" => " some event name "})
assert goal.event_name == "some event name"
end
test "create/2 creates pageview goal and adds a leading slash if missing" do
site = insert(:site)
{:ok, goal} = Goals.create(site, %{"page_path" => "foo bar"})
assert goal.page_path == "/foo bar"
end
test "create/2 validates goal name is at most 120 chars" do
site = insert(:site)
assert {:error, changeset} = Goals.create(site, %{"event_name" => String.duplicate("a", 130)})
assert {"should be at most %{count} character(s)", _} = changeset.errors[:event_name]
end
test "create/2 fails to create the same pageview goal twice" do
site = insert(:site)
{:ok, _} = Goals.create(site, %{"page_path" => "foo bar"})
assert {:error, changeset} = Goals.create(site, %{"page_path" => "foo bar"})
assert {"has already been taken", _} = changeset.errors[:page_path]
end
test "create/2 fails to create the same custom event goal twice" do
site = insert(:site)
{:ok, _} = Goals.create(site, %{"event_name" => "foo bar"})
assert {:error, changeset} = Goals.create(site, %{"event_name" => "foo bar"})
assert {"has already been taken", _} = changeset.errors[:event_name]
end
test "create/2 fails to create the same currency goal twice" do
site = insert(:site)
{:ok, _} = Goals.create(site, %{"event_name" => "foo bar", "currency" => "EUR"})
assert {:error, changeset} =
Goals.create(site, %{"event_name" => "foo bar", "currency" => "EUR"})
assert {"has already been taken", _} = changeset.errors[:event_name]
end
@tag :ee_only
test "create/2 sets site.updated_at for revenue goal" do
site_1 = insert(:site, updated_at: DateTime.add(DateTime.utc_now(), -3600))
{:ok, _goal_1} = Goals.create(site_1, %{"event_name" => "Checkout", "currency" => "BRL"})
assert NaiveDateTime.compare(site_1.updated_at, Plausible.Repo.reload!(site_1).updated_at) ==
:lt
site_2 = insert(:site, updated_at: DateTime.add(DateTime.utc_now(), -3600))
{:ok, _goal_2} = Goals.create(site_2, %{"event_name" => "Read Article", "currency" => nil})
assert NaiveDateTime.compare(site_2.updated_at, Plausible.Repo.reload!(site_2).updated_at) ==
:eq
end
@tag :ee_only
test "create/2 creates revenue goal" do
site = insert(:site)
{:ok, goal} = Goals.create(site, %{"event_name" => "Purchase", "currency" => "EUR"})
assert goal.event_name == "Purchase"
assert goal.page_path == nil
assert goal.currency == :EUR
end
@tag :ee_only
test "create/2 returns error when site does not have access to revenue goals" do
user = insert(:user, subscription: build(:growth_subscription))
site = insert(:site, members: [user])
{:error, :upgrade_required} =
Goals.create(site, %{"event_name" => "Purchase", "currency" => "EUR"})
end
@tag :ee_only
test "create/2 fails for unknown currency code" do
site = insert(:site)
assert {:error, changeset} =
Goals.create(site, %{"event_name" => "Purchase", "currency" => "Euro"})
assert [currency: {"is invalid", _}] = changeset.errors
end
@tag :ee_only
test "list_revenue_goals/1 lists event_names and currencies for each revenue goal" do
site = insert(:site)
Goals.create(site, %{"event_name" => "One", "currency" => "EUR"})
Goals.create(site, %{"event_name" => "Two", "currency" => "EUR"})
Goals.create(site, %{"event_name" => "Three", "currency" => "USD"})
Goals.create(site, %{"event_name" => "Four"})
Goals.create(site, %{"page_path" => "/some-page"})
revenue_goals = Goals.list_revenue_goals(site)
assert length(revenue_goals) == 3
assert %{event_name: "One", currency: :EUR} in revenue_goals
assert %{event_name: "Two", currency: :EUR} in revenue_goals
assert %{event_name: "Three", currency: :USD} in revenue_goals
end
test "create/2 clears currency for pageview goals" do
site = insert(:site)
{:ok, goal} = Goals.create(site, %{"page_path" => "/purchase", "currency" => "EUR"})
assert goal.event_name == nil
assert goal.page_path == "/purchase"
assert goal.currency == nil
end
test "for_site/1 returns trimmed input even if it was saved with trailing whitespace" do
site = insert(:site)
insert(:goal, %{site: site, event_name: " Signup "})
insert(:goal, %{site: site, page_path: " /Signup "})
goals = Goals.for_site(site)
assert [%{page_path: "/Signup"}, %{event_name: "Signup"}] = goals
end
test "goals are present after domain change" do
site = insert(:site)
insert(:goal, %{site: site, event_name: " Signup "})
insert(:goal, %{site: site, page_path: " /Signup "})
{:ok, site} = Plausible.Site.Domain.change(site, "goals.example.com")
assert [_, _] = Goals.for_site(site)
end
test "goals are removed when site is deleted" do
site = insert(:site)
insert(:goal, %{site: site, event_name: " Signup "})
insert(:goal, %{site: site, page_path: " /Signup "})
Plausible.Site.Removal.run(site.domain)
assert [] = Goals.for_site(site)
end
test "goals can be deleted" do
site = insert(:site)
goal = insert(:goal, %{site: site, event_name: " Signup "})
:ok = Goals.delete(goal.id, site)
assert [] = Goals.for_site(site)
end
on_ee do
test "goals can be fetched with funnel count preloaded" do
site = insert(:site)
goals =
Enum.map(1..4, fn i ->
{:ok, g} = Goals.create(site, %{"page_path" => "/#{i}"})
g
end)
{:ok, %{id: funnel_id1}} =
Plausible.Funnels.create(
site,
"Funnel1",
[
%{"goal_id" => Enum.at(goals, 1).id},
%{"goal_id" => Enum.at(goals, 2).id},
%{"goal_id" => Enum.at(goals, 3).id}
]
)
{:ok, %{id: funnel_id2}} =
Plausible.Funnels.create(
site,
"Funnel2",
[
%{"goal_id" => Enum.at(goals, 1).id},
%{"goal_id" => Enum.at(goals, 3).id}
]
)
assert [goal, _, _, _] = Goals.for_site(site, preload_funnels?: false)
assert %Ecto.Association.NotLoaded{} = goal.funnels
assert [goal, _, _, _] = Goals.for_site(site, preload_funnels?: true)
assert [%{id: ^funnel_id1}, %{id: ^funnel_id2}] = goal.funnels
end
test "deleting goals with funnels triggers funnel reduction" do
site = insert(:site)
{:ok, g1} = Goals.create(site, %{"page_path" => "/1"})
{:ok, g2} = Goals.create(site, %{"page_path" => "/2"})
{:ok, g3} = Goals.create(site, %{"page_path" => "/3"})
{:ok, f1} =
Plausible.Funnels.create(
site,
"Funnel 3 steps",
[
%{"goal_id" => g1.id},
%{"goal_id" => g2.id},
%{"goal_id" => g3.id}
]
)
{:ok, f2} =
Plausible.Funnels.create(
site,
"Funnel 2 steps",
[
%{"goal_id" => g1.id},
%{"goal_id" => g2.id}
]
)
:ok = Goals.delete(g1.id, site)
assert f1 = Plausible.Funnels.get(site.id, f1.id)
assert Enum.count(f1.steps) == 2
refute Plausible.Funnels.get(site.id, f2.id)
assert Repo.all(from(fs in Plausible.Funnel.Step, where: fs.funnel_id == ^f2.id)) == []
assert [^g3, ^g2] = Goals.for_site(site)
end
end
test "must be either page_path or event_name" do
site = insert(:site)
assert {:error, changeset} =
Goals.create(site, %{"page_path" => "/foo", "event_name" => "/foo"})
assert {"cannot co-exist with page_path", _} = changeset.errors[:event_name]
end
end