| defmodule Plausible.PropsTest do |
| use Plausible.DataCase |
|
|
| test "allow/2 returns error when user plan does not include props" do |
| user = new_user() |> subscribe_to_growth_plan() |
| site = new_site(owner: user) |
|
|
| assert {:error, :upgrade_required} = Plausible.Props.allow(site, "my-prop-1") |
| assert %Plausible.Site{allowed_event_props: nil} = Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow/2 adds props to the array" do |
| site = new_site() |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-1") |
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-2") |
|
|
| assert %Plausible.Site{allowed_event_props: ["my-prop-2", "my-prop-1"]} = |
| Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow/2 takes a single prop or multiple" do |
| site = new_site() |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-1") |
| assert {:ok, site} = Plausible.Props.allow(site, ["my-prop-3", "my-prop-2"]) |
|
|
| assert %Plausible.Site{allowed_event_props: ["my-prop-3", "my-prop-2", "my-prop-1"]} = |
| Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow/2 trims trailing whitespaces" do |
| site = new_site() |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, " my-prop-1 ") |
| assert %Plausible.Site{allowed_event_props: ["my-prop-1"]} = Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow/2 fails when prop list is too long" do |
| site = new_site() |
| props = for i <- 1..300, do: "my-prop-#{i}" |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, props) |
| assert {:error, changeset} = Plausible.Props.allow(site, "my-prop-301") |
|
|
| assert {"should have at most %{count} item(s)", |
| [count: 300, validation: :length, kind: :max, type: :list]} == |
| changeset.errors[:allowed_event_props] |
| end |
|
|
| test "allow/2 fails when prop key is too long" do |
| site = new_site() |
|
|
| long_prop = String.duplicate("a", 301) |
| assert {:error, changeset} = Plausible.Props.allow(site, long_prop) |
|
|
| assert {"must be between 1 and 300 characters", [validation: :length, type: :string]} == |
| changeset.errors[:allowed_event_props] |
| end |
|
|
| test "allow/2 fails when prop key is empty" do |
| site = new_site() |
|
|
| assert {:error, changeset} = Plausible.Props.allow(site, "") |
|
|
| assert {"must be between 1 and 300 characters", [validation: :length, type: :string]} == |
| changeset.errors[:allowed_event_props] |
|
|
| assert {:error, changeset} = Plausible.Props.allow(site, " ") |
|
|
| assert {"must be between 1 and 300 characters", [validation: :length, type: :string]} == |
| changeset.errors[:allowed_event_props] |
| end |
|
|
| test "allow/2 does not fail when prop key is already in the list" do |
| site = new_site() |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-1") |
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-1") |
| assert %Plausible.Site{allowed_event_props: ["my-prop-1"]} = Plausible.Repo.reload!(site) |
| end |
|
|
| test "disallow/2 removes the prop from the array" do |
| site = new_site() |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-1") |
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-2") |
| assert {:ok, site} = Plausible.Props.disallow(site, "my-prop-2") |
| assert %Plausible.Site{allowed_event_props: ["my-prop-1"]} = Plausible.Repo.reload!(site) |
| end |
|
|
| test "disallow/2 does not fail when prop is not in the list" do |
| site = new_site() |
|
|
| assert {:ok, site} = Plausible.Props.allow(site, "my-prop-1") |
| assert {:ok, site} = Plausible.Props.disallow(site, "my-prop-2") |
| assert %Plausible.Site{allowed_event_props: ["my-prop-1"]} = Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow_existing_props/2 returns error when user plan does not include props" do |
| user = new_user() |> subscribe_to_growth_plan() |
| site = new_site(owner: user) |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount"], |
| "meta.value": ["500"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "logged_in"], |
| "meta.value": ["100", "false"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "is_customer"], |
| "meta.value": ["100", "false"] |
| ) |
| ]) |
|
|
| assert {:error, :upgrade_required} = Plausible.Props.allow_existing_props(site) |
| assert %Plausible.Site{allowed_event_props: nil} = Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow_existing_props/1 saves the most frequent prop keys" do |
| site = new_site() |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount"], |
| "meta.value": ["500"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "logged_in"], |
| "meta.value": ["100", "false"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "is_customer"], |
| "meta.value": ["100", "false"] |
| ) |
| ]) |
|
|
| {:ok, site} = Plausible.Props.allow_existing_props(site) |
|
|
| assert %Plausible.Site{allowed_event_props: ["amount", "logged_in", "is_customer"]} = |
| Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow_existing_props/1 skips invalid keys" do |
| site = new_site() |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", String.duplicate("a", 301)], |
| "meta.value": ["500", "true"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "logged_in"], |
| "meta.value": ["100", "false"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "is_customer"], |
| "meta.value": ["100", "false"] |
| ) |
| ]) |
|
|
| {:ok, site} = Plausible.Props.allow_existing_props(site) |
|
|
| assert %Plausible.Site{allowed_event_props: ["amount", "logged_in", "is_customer"]} = |
| Plausible.Repo.reload!(site) |
| end |
|
|
| test "allow_existing_props/1 can be run multiple times" do |
| site = new_site() |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount"], |
| "meta.value": ["500"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "logged_in"], |
| "meta.value": ["100", "false"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "is_customer"], |
| "meta.value": ["100", "false"] |
| ) |
| ]) |
|
|
| {:ok, %Plausible.Site{allowed_event_props: ["amount", "logged_in", "is_customer"]}} = |
| Plausible.Props.allow_existing_props(site) |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "os"], |
| "meta.value": ["500", "Windows"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "logged_in", "with_error"], |
| "meta.value": ["100", "false", "true"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "is_customer", "first_time_customer"], |
| "meta.value": ["100", "false", "true"] |
| ) |
| ]) |
|
|
| {:ok, |
| %Plausible.Site{ |
| allowed_event_props: [ |
| "amount", |
| "logged_in", |
| "is_customer", |
| "os", |
| "with_error", |
| "first_time_customer" |
| ] |
| }} = Plausible.Props.allow_existing_props(site) |
| end |
|
|
| test "suggest_keys_to_allow/2 returns prop keys from events" do |
| site = new_site() |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "os"], |
| "meta.value": ["500", "Windows"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "logged_in", "with_error"], |
| "meta.value": ["100", "false", "true"] |
| ), |
| build(:event, |
| name: "Payment", |
| "meta.key": ["amount", "is_customer", "first_time_customer"], |
| "meta.value": ["100", "false", "true"] |
| ) |
| ]) |
|
|
| assert ["amount", "first_time_customer", "is_customer", "logged_in", "os", "with_error"] == |
| site |> Plausible.Props.suggest_keys_to_allow() |> Enum.sort() |
| end |
|
|
| on_ee do |
| test "suggest_keys_to_allow/2 for consolidated view queries events across all included sites" do |
| {:ok, team} = new_user() |> Plausible.Teams.get_or_create() |
| site1 = new_site(team: team) |
| site2 = new_site(team: team) |
| consolidated_view = new_consolidated_view(team) |
|
|
| populate_stats(site1, [ |
| build(:pageview, "meta.key": ["a", "b"], "meta.value": ["A", "B"]) |
| ]) |
|
|
| populate_stats(site2, [ |
| build(:pageview, "meta.key": ["a", "c"], "meta.value": ["A", "C"]) |
| ]) |
|
|
| assert ["a", "b", "c"] == |
| Plausible.Props.suggest_keys_to_allow(consolidated_view) |> Enum.sort() |
| end |
| end |
|
|
| test "suggest_keys_to_allow/2 does not return internal prop keys from special event types" do |
| site = new_site() |
|
|
| populate_stats(site, [ |
| build(:event, |
| name: "File Download", |
| "meta.key": ["url", "logged_in"], |
| "meta.value": ["http://file.test", "false"] |
| ), |
| build(:event, |
| name: "Outbound Link: Click", |
| "meta.key": ["url", "first_time_customer"], |
| "meta.value": ["http://link.test", "true"] |
| ), |
| build(:event, |
| name: "404", |
| "meta.key": ["path", "with_error"], |
| "meta.value": ["/i-dont-exist", "true"] |
| ), |
| build(:event, |
| name: "WP Search Queries", |
| "meta.key": ["search_query", "result_count"], |
| "meta.value": ["something", "12"] |
| ), |
| build(:event, |
| name: "WP Form Completions", |
| "meta.key": ["path"], |
| "meta.value": ["/contact"] |
| ) |
| ]) |
|
|
| assert ["first_time_customer", "logged_in", "result_count", "with_error"] == |
| site |> Plausible.Props.suggest_keys_to_allow() |> Enum.sort() |
| end |
|
|
| test "configured?/1 returns whether the site has allow at least one prop" do |
| site = new_site() |
| refute Plausible.Props.configured?(site) |
|
|
| {:ok, site} = Plausible.Props.allow(site, "hello-world") |
| assert Plausible.Props.configured?(site) |
|
|
| {:ok, site} = Plausible.Props.disallow(site, "hello-world") |
| refute Plausible.Props.configured?(site) |
| end |
| end |
|
|