diff --git a/CHANGELOG.md b/CHANGELOG.md index 899ad0bf7822..509c6254975e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ All notable changes to this project will be documented in this file. - Fixed issue with site guests in Editor role and team members in Editor role not being able to change the domain of site - Fixed direct dashboard links that use legacy dashboard filters containing URL encoded special characters (e.g. character `ê` in the legacy filter `?page=%C3%AA`) - Fix bug with tracker script config cache that made requests for certain cached scripts give error 500 +- Fix issue with all non-interactive events being counted as interactive ## v3.1.0 - 2025-11-13 diff --git a/lib/mix/tasks/send_pageview.ex b/lib/mix/tasks/send_pageview.ex index b25cf740ab4f..0ab839ff0011 100644 --- a/lib/mix/tasks/send_pageview.ex +++ b/lib/mix/tasks/send_pageview.ex @@ -18,6 +18,7 @@ defmodule Mix.Tasks.SendPageview do @default_event "pageview" @default_props "{}" @default_queryparams "" + @default_interactive true @options [ ip: :string, user_agent: :string, @@ -30,7 +31,8 @@ defmodule Mix.Tasks.SendPageview do props: :string, revenue_currency: :string, revenue_amount: :string, - queryparams: :string + queryparams: :string, + interactive: :string ] def run(opts) do @@ -92,6 +94,13 @@ defmodule Mix.Tasks.SendPageview do hostname = Keyword.get(opts, :hostname, domain) queryparams = Keyword.get(opts, :queryparams, @default_queryparams) + interactive = + if Keyword.get(opts, :interactive) == "false" do + false + else + @default_interactive + end + revenue = if Keyword.get(opts, :revenue_currency) do %{ @@ -106,7 +115,8 @@ defmodule Mix.Tasks.SendPageview do domain: domain, referrer: referrer, props: props, - revenue: revenue + revenue: revenue, + interactive: interactive } end diff --git a/lib/plausible/clickhouse_event_v2.ex b/lib/plausible/clickhouse_event_v2.ex index a8c9d2974f61..7e2d8861a22f 100644 --- a/lib/plausible/clickhouse_event_v2.ex +++ b/lib/plausible/clickhouse_event_v2.ex @@ -70,7 +70,8 @@ defmodule Plausible.ClickhouseEventV2 do :revenue_source_amount, :revenue_source_currency, :revenue_reporting_amount, - :revenue_reporting_currency + :revenue_reporting_currency, + :interactive? ] ) |> validate_required([:name, :site_id, :hostname, :pathname, :user_id, :timestamp]) diff --git a/lib/plausible/event/system_events.ex b/lib/plausible/event/system_events.ex new file mode 100644 index 000000000000..c78d9ed060af --- /dev/null +++ b/lib/plausible/event/system_events.ex @@ -0,0 +1,101 @@ +defmodule Plausible.Event.SystemEvents do + @moduledoc """ + System events are events that require at least one form of special treatment by the application. + They are distinguished by event name. + + For some system events, the tracking API may reject events that don't match the expected format + (e.g. engagement events without scroll depth or engagement time defined). + + For other system events, it may accept the event (e.g. "Outbound Link: Click" with the url prop not set). + + System events may have corresponding system-managed goals, in which case the goal name and event name will be the same + (e.g. "Outbound Link: Click" goal is managed by the application). The system will only be able to manage these goals properly + if they are not renamed by the user. + """ + @pageview_event_name "pageview" + @engagement_event_name "engagement" + + @outbound_link_click_event_name "Outbound Link: Click" + @cloaked_link_click_event_name "Cloaked Link: Click" + @file_download_link_click_event_name "File Download" + + @error_404_event_name "404" + @wordpress_form_completions_event_name "WP Form Completions" + @form_submission_event_name "Form: Submission" + + @all_system_events [ + @pageview_event_name, + @engagement_event_name, + @outbound_link_click_event_name, + @cloaked_link_click_event_name, + @file_download_link_click_event_name, + @error_404_event_name, + @wordpress_form_completions_event_name, + @form_submission_event_name + ] + + @interactive_events @all_system_events + + @events_with_url_prop [ + @outbound_link_click_event_name, + @cloaked_link_click_event_name, + @file_download_link_click_event_name + ] + + @events_with_path_prop [ + @error_404_event_name, + @wordpress_form_completions_event_name, + @form_submission_event_name + ] + + @events_with_engagement_props [ + @engagement_event_name + ] + + def events() do + @all_system_events + end + + def events_with_interactive_always_true() do + @interactive_events + end + + def events_with_url_prop() do + @events_with_url_prop + end + + def events_with_path_prop() do + @events_with_path_prop + end + + def events_with_engagement_props() do + @events_with_engagement_props + end + + @spec special_events_for_prop_key(String.t()) :: [String.t()] + def special_events_for_prop_key("url"), do: events_with_url_prop() + def special_events_for_prop_key("path"), do: events_with_path_prop() + + @doc """ + Checks if the event name is for a system event / system goal that should have the event.props.path synced with the event.pathname property. + + ### Examples + iex> sync_props_path_with_pathname?("404", [{"path", "/foo"}]) + false + + Note: Should not override event.props.path if it is set deliberately to nil + iex> sync_props_path_with_pathname?("404", [{"path", nil}]) + false + + iex> sync_props_path_with_pathname?("404", [{"other", "value"}]) + true + + iex> sync_props_path_with_pathname?("404", []) + true + """ + @spec sync_props_path_with_pathname?(String.t(), [{String.t(), String.t()}]) :: boolean() + def sync_props_path_with_pathname?(event_name, props_in_request) do + event_name in events_with_path_prop() and + not Enum.any?(props_in_request, fn {k, _} -> k == "path" end) + end +end diff --git a/lib/plausible/exports.ex b/lib/plausible/exports.ex index ba6bdcfbcd8e..77d770593045 100644 --- a/lib/plausible/exports.ex +++ b/lib/plausible/exports.ex @@ -564,7 +564,7 @@ defmodule Plausible.Exports do fragment( "if(? in ?, ?, '')", e.name, - ^Plausible.Goals.SystemGoals.goals_with_url(), + ^Plausible.Event.SystemEvents.events_with_url_prop(), get_by_key(e, :meta, "url") ), :link_url @@ -573,7 +573,7 @@ defmodule Plausible.Exports do fragment( "if(? in ?, ?, '')", e.name, - ^Plausible.Goals.SystemGoals.goals_with_path(), + ^Plausible.Event.SystemEvents.events_with_path_prop(), get_by_key(e, :meta, "path") ), :path diff --git a/lib/plausible/goals/system_goals.ex b/lib/plausible/goals/system_goals.ex deleted file mode 100644 index 0c923ac59026..000000000000 --- a/lib/plausible/goals/system_goals.ex +++ /dev/null @@ -1,48 +0,0 @@ -defmodule Plausible.Goals.SystemGoals do - @moduledoc """ - This module contains logic for special goals - """ - - # Special system goals which can be filtered by 'url' custom property - @goals_with_url ["Outbound Link: Click", "Cloaked Link: Click", "File Download"] - - # Special system goals which can be filtered by 'path' custom property - @goals_with_path ["404", "WP Form Completions", "Form: Submission"] - - @spec goals_with_url() :: [String.t()] - def goals_with_url() do - @goals_with_url - end - - @spec goals_with_path() :: [String.t()] - def goals_with_path() do - @goals_with_path - end - - @spec special_goals_for(String.t()) :: [String.t()] - def special_goals_for("event:props:url"), do: goals_with_url() - def special_goals_for("event:props:path"), do: goals_with_path() - - @doc """ - Checks if the event name is for a special goal that should have the event.props.path synced with the event.pathname property. - - ### Examples - iex> sync_props_path_with_pathname?("404", [{"path", "/foo"}]) - false - - Note: Should not override event.props.path if it is set deliberately to nil - iex> sync_props_path_with_pathname?("404", [{"path", nil}]) - false - - iex> sync_props_path_with_pathname?("404", [{"other", "value"}]) - true - - iex> sync_props_path_with_pathname?("404", []) - true - """ - @spec sync_props_path_with_pathname?(String.t(), [{String.t(), String.t()}]) :: boolean() - def sync_props_path_with_pathname?(event_name, props_in_request) do - event_name in goals_with_path() and - not Enum.any?(props_in_request, fn {k, _} -> k == "path" end) - end -end diff --git a/lib/plausible/ingestion/request.ex b/lib/plausible/ingestion/request.ex index cd58d26b8f19..e8b15a97f152 100644 --- a/lib/plausible/ingestion/request.ex +++ b/lib/plausible/ingestion/request.ex @@ -182,7 +182,7 @@ defmodule Plausible.Ingestion.Request do end defp maybe_set_props_path_to_pathname(props_in_request, changeset) do - if Plausible.Goals.SystemGoals.sync_props_path_with_pathname?( + if Plausible.Event.SystemEvents.sync_props_path_with_pathname?( Changeset.get_field(changeset, :event_name), props_in_request ) do @@ -259,12 +259,15 @@ defmodule Plausible.Ingestion.Request do end defp put_interactive(changeset, %{} = request_body) do - case request_body["i"] || request_body["interactive"] do - interactive? when is_boolean(interactive?) -> - Changeset.put_change(changeset, :interactive?, interactive?) + can_be_marked_as_non_interactive? = + Changeset.get_field(changeset, :event_name) not in Plausible.Event.SystemEvents.events_with_interactive_always_true() - _ -> - changeset + if can_be_marked_as_non_interactive? and + (request_body["i"] == false or + request_body["interactive"] == false) do + Changeset.put_change(changeset, :interactive?, false) + else + changeset end end diff --git a/lib/plausible/stats/imported/base.ex b/lib/plausible/stats/imported/base.ex index 1a354c56d36d..1580b9e42df3 100644 --- a/lib/plausible/stats/imported/base.ex +++ b/lib/plausible/stats/imported/base.ex @@ -123,21 +123,26 @@ defmodule Plausible.Stats.Imported.Base do end defp do_decide_custom_prop_table(query, property) do - has_required_name_filter? = + "event:props:" <> prop_key = property + + has_required_event_or_goal_name_filter? = query.filters |> Enum.flat_map(fn - [:is, "event:name", names | _rest] -> names - [:is, "event:goal", names | _rest] -> names + [:is, "event:name", event_names | _rest] -> event_names + [:is, "event:goal", goal_names | _rest] -> goal_names _ -> [] end) - |> Enum.any?(&(&1 in Plausible.Goals.SystemGoals.special_goals_for(property))) + |> Enum.any?(fn event_or_goal_name -> + event_or_goal_name in Plausible.Event.SystemEvents.special_events_for_prop_key(prop_key) + end) has_unsupported_filters? = query.filters |> dimensions_used_in_filters() |> Enum.any?(&(&1 not in [property, "event:name", "event:goal"])) - if has_required_name_filter? and not has_unsupported_filters? do + if has_required_event_or_goal_name_filter? and + not has_unsupported_filters? do ["imported_custom_events"] else [] diff --git a/lib/plausible/stats/imported/imported.ex b/lib/plausible/stats/imported/imported.ex index 29f9d96da3e7..a88080902d32 100644 --- a/lib/plausible/stats/imported/imported.ex +++ b/lib/plausible/stats/imported/imported.ex @@ -18,8 +18,8 @@ defmodule Plausible.Stats.Imported do Usually, when no filters are used, the imported schema supports the query. There is one exception though - breakdown by a custom property. We are currently importing only two custom properties - `url` and `path`. - Both these properties can only be used with their special goal filter - (see Plausible.Goals.SystemGoals). + Both these properties can only be used with their particular `event:name` + filter or the corresponding goal filter (see Plausible.Event.SystemEvents). """ def schema_supports_query?(query) do length(Imported.Base.decide_tables(query)) > 0 diff --git a/test/plausible/event/system_events_test.exs b/test/plausible/event/system_events_test.exs new file mode 100644 index 000000000000..f1cd74e4ecf9 --- /dev/null +++ b/test/plausible/event/system_events_test.exs @@ -0,0 +1,5 @@ +defmodule Plausible.Event.SystemEventsTest do + use ExUnit.Case, async: true + + doctest Plausible.Event.SystemEvents, import: true +end diff --git a/test/plausible/goals_test.exs b/test/plausible/goals_test.exs index 78ded940c71d..7568b2322455 100644 --- a/test/plausible/goals_test.exs +++ b/test/plausible/goals_test.exs @@ -2,8 +2,6 @@ defmodule Plausible.GoalsTest do use Plausible.DataCase alias Plausible.Goals - doctest Plausible.Goals.SystemGoals, import: true - test "create/2 creates goals and trims input" do site = new_site() {:ok, goal} = Goals.create(site, %{"page_path" => "/foo bar "}) diff --git a/test/plausible/ingestion/event_test.exs b/test/plausible/ingestion/event_test.exs index bb0a2fbf4bec..71f9d2affb07 100644 --- a/test/plausible/ingestion/event_test.exs +++ b/test/plausible/ingestion/event_test.exs @@ -394,6 +394,30 @@ defmodule Plausible.Ingestion.EventTest do assert dropped.drop_reason == :no_session_for_engagement end + for {input, expected} <- [ + {0, true}, + {nil, true}, + {"invalid", true}, + {true, true}, + {false, false} + ] do + test "parses events interactive value #{inspect(input)} to #{inspect(expected)}" do + site = new_site() + + payload = %{ + name: "ping", + url: "http://#{site.domain}", + interactive: unquote(input) + } + + conn = build_conn(:post, "/api/events", payload) + assert {:ok, request, _conn} = Request.build(conn) + + assert {:ok, %{buffered: [event], dropped: []}} = Event.build_and_buffer(request) + assert event.clickhouse_event.interactive? == unquote(expected) + end + end + @tag :ee_only test "saves revenue amount" do site = new_site() diff --git a/test/plausible/ingestion/request_test.exs b/test/plausible/ingestion/request_test.exs index 7df7261d4eea..7426926a2546 100644 --- a/test/plausible/ingestion/request_test.exs +++ b/test/plausible/ingestion/request_test.exs @@ -292,7 +292,7 @@ defmodule Plausible.Ingestion.RequestTest do assert request.pathname == "/pictures/index.html#foo" end - for event_name <- Plausible.Goals.SystemGoals.goals_with_path() do + for event_name <- Plausible.Event.SystemEvents.events_with_path_prop() do test "event.props.path is synced from event.pathname for special path-based event '#{event_name}'" do payload = %{ name: unquote(event_name), @@ -505,20 +505,63 @@ defmodule Plausible.Ingestion.RequestTest do assert {:error, _} = exceeding_read_limit end - test "respects interactive parameter" do - params = %{ - name: "pageview", - domain: "dummy.site", - url: "http://dummy.site/index.html", - interactive: false - } + for event_name <- + Plausible.Event.SystemEvents.events_with_interactive_always_true() -- + Plausible.Event.SystemEvents.events_with_engagement_props() do + test "ignores interactive: false parameter for #{event_name}" do + params = %{ + name: unquote(event_name), + domain: "dummy.site", + url: "http://dummy.site/index.html", + interactive: false + } - assert {:ok, request, _conn} = - build_conn(:post, "/api/events", params) - |> put_req_header("user-agent", "Mozilla") - |> Request.build() + assert {:ok, request, _conn} = + build_conn(:post, "/api/events", params) + |> put_req_header("user-agent", "Mozilla") + |> Request.build() + + assert request.interactive? + end + end + + for event_name <- Plausible.Event.SystemEvents.events_with_engagement_props() do + test "ignores interactive: false parameter for #{event_name}" do + params = %{ + name: unquote(event_name), + domain: "dummy.site", + url: "http://dummy.site/index.html", + sd: 10, + e: 100, + interactive: false + } + + assert {:ok, request, _conn} = + build_conn(:post, "/api/events", params) + |> put_req_header("user-agent", "Mozilla") + |> Request.build() - refute request.interactive? + assert request.interactive? + end + end + + for param_key <- [:interactive, :i] do + test "allows marking user-defined custom events as non-interactive with payload #{Atom.to_string(param_key)}: false" do + params = + %{ + name: "ping", + domain: "dummy.site", + url: "http://dummy.site/index.html" + } + |> Map.put(unquote(param_key), false) + + assert {:ok, request, _conn} = + build_conn(:post, "/api/events", params) + |> put_req_header("user-agent", "Mozilla") + |> Request.build() + + refute request.interactive? + end end @tag :ee_only diff --git a/test/plausible_web/controllers/api/external_stats_controller/breakdown_test.exs b/test/plausible_web/controllers/api/external_stats_controller/breakdown_test.exs index 0aabad3517fd..b13b94870e44 100644 --- a/test/plausible_web/controllers/api/external_stats_controller/breakdown_test.exs +++ b/test/plausible_web/controllers/api/external_stats_controller/breakdown_test.exs @@ -3371,25 +3371,25 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do assert %{"source" => "Google", "events" => 1} = breakdown_and_first.("visit:source") end - for goal_name <- Plausible.Goals.SystemGoals.goals_with_url() do - test "returns url breakdown for #{goal_name} goal", %{conn: conn, site: site} do - insert(:goal, event_name: unquote(goal_name), site: site) + for event_name <- Plausible.Event.SystemEvents.events_with_url_prop() do + test "returns url breakdown for #{event_name} goal", %{conn: conn, site: site} do + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["url"], "meta.value": ["https://one.com"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, link_url: "https://one.com" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, link_url: "https://two.com" @@ -3407,7 +3407,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do "site_id" => site.domain, "period" => "day", "property" => "event:props:url", - "filters" => "event:goal==#{unquote(goal_name)}", + "filters" => "event:goal==#{unquote(event_name)}", "metrics" => "visitors,events,conversion_rate", "with_imported" => "true" }) @@ -3431,25 +3431,25 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do end end - for goal_name <- Plausible.Goals.SystemGoals.goals_with_path() do - test "returns path breakdown for #{goal_name} goal", %{conn: conn, site: site} do - insert(:goal, event_name: unquote(goal_name), site: site) + for event_name <- Plausible.Event.SystemEvents.events_with_path_prop() do + test "returns path breakdown for #{event_name} goal", %{conn: conn, site: site} do + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["path"], "meta.value": ["/one"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, path: "/one" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, path: "/two" @@ -3467,7 +3467,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do "site_id" => site.domain, "period" => "day", "property" => "event:props:path", - "filters" => "event:goal==#{unquote(goal_name)}", + "filters" => "event:goal==#{unquote(event_name)}", "metrics" => "visitors,events,conversion_rate", "with_imported" => "true" }) diff --git a/test/plausible_web/controllers/api/external_stats_controller/query_imported_test.exs b/test/plausible_web/controllers/api/external_stats_controller/query_imported_test.exs index 9cbaab027326..71e162723396 100644 --- a/test/plausible_web/controllers/api/external_stats_controller/query_imported_test.exs +++ b/test/plausible_web/controllers/api/external_stats_controller/query_imported_test.exs @@ -683,25 +683,25 @@ defmodule PlausibleWeb.Api.ExternalStatsController.QueryImportedTest do breakdown_and_first.("visit:source") end - for goal_name <- Plausible.Goals.SystemGoals.goals_with_url() do - test "returns url breakdown for #{goal_name} goal", %{conn: conn, site: site} do - insert(:goal, event_name: unquote(goal_name), site: site) + for event_name <- Plausible.Event.SystemEvents.events_with_url_prop() do + test "returns url breakdown for #{event_name} goal", %{conn: conn, site: site} do + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["url"], "meta.value": ["https://one.com"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, link_url: "https://one.com" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, link_url: "https://two.com" @@ -721,7 +721,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.QueryImportedTest do "date_range" => "all", "dimensions" => ["event:props:url"], "filters" => [ - ["is", "event:goal", [unquote(goal_name)]] + ["is", "event:goal", [unquote(event_name)]] ], "include" => %{"imports" => true} }) @@ -736,25 +736,25 @@ defmodule PlausibleWeb.Api.ExternalStatsController.QueryImportedTest do end end - for goal_name <- Plausible.Goals.SystemGoals.goals_with_path() do - test "returns path breakdown for #{goal_name} goal", %{conn: conn, site: site} do - insert(:goal, event_name: unquote(goal_name), site: site) + for event_name <- Plausible.Event.SystemEvents.events_with_path_prop() do + test "returns path breakdown for #{event_name} goal", %{conn: conn, site: site} do + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["path"], "meta.value": ["/one"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, path: "/one" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, path: "/two" @@ -774,7 +774,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.QueryImportedTest do "date_range" => "all", "dimensions" => ["event:props:path"], "filters" => [ - ["is", "event:goal", [unquote(goal_name)]] + ["is", "event:goal", [unquote(event_name)]] ], "include" => %{"imports" => true} }) diff --git a/test/plausible_web/controllers/api/stats_controller/custom_prop_breakdown_test.exs b/test/plausible_web/controllers/api/stats_controller/custom_prop_breakdown_test.exs index b2c0ff43bf70..d41cfbb60596 100644 --- a/test/plausible_web/controllers/api/stats_controller/custom_prop_breakdown_test.exs +++ b/test/plausible_web/controllers/api/stats_controller/custom_prop_breakdown_test.exs @@ -1260,25 +1260,25 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do ] end - for goal_name <- Plausible.Goals.SystemGoals.goals_with_path() do - test "returns path breakdown for #{goal_name} goal", %{conn: conn, site: site} do - insert(:goal, event_name: unquote(goal_name), site: site) + for event_name <- Plausible.Event.SystemEvents.events_with_path_prop() do + test "returns path breakdown for #{event_name} goal", %{conn: conn, site: site} do + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["path"], "meta.value": ["/some/path/first.bin"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, path: "/some/path/first.bin" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, path: "/some/path/second.bin" @@ -1293,7 +1293,7 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do filters = Jason.encode!([ - [:is, "event:goal", [unquote(goal_name)]] + [:is, "event:goal", [unquote(event_name)]] ]) conn = @@ -1319,25 +1319,25 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do end end - for goal_name <- Plausible.Goals.SystemGoals.goals_with_url() do - test "returns url breakdown for #{goal_name} goal", %{conn: conn, site: site} do - insert(:goal, event_name: unquote(goal_name), site: site) + for event_name <- Plausible.Event.SystemEvents.events_with_url_prop() do + test "returns url breakdown for #{event_name} goal", %{conn: conn, site: site} do + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["url"], "meta.value": ["https://one.com"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, link_url: "https://one.com" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, link_url: "https://two.com" @@ -1352,7 +1352,7 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do filters = Jason.encode!([ - [:is, "event:goal", [unquote(goal_name)]] + [:is, "event:goal", [unquote(event_name)]] ]) conn = @@ -1378,28 +1378,28 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do end end - for goal_name <- ["Outbound Link: Click", "File Download", "Cloaked Link: Click"] do - test "returns url breakdown for #{goal_name} goal with a url filter", %{ + for event_name <- Plausible.Event.SystemEvents.events_with_url_prop() do + test "returns url breakdown for #{event_name} goal with a url filter", %{ conn: conn, site: site } do - insert(:goal, event_name: unquote(goal_name), site: site) + insert(:goal, event_name: unquote(event_name), site: site) site_import = insert(:site_import, site: site) populate_stats(site, site_import.id, [ build(:event, - name: unquote(goal_name), + name: unquote(event_name), "meta.key": ["url"], "meta.value": ["https://one.com"] ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 2, events: 5, link_url: "https://one.com" ), build(:imported_custom_events, - name: unquote(goal_name), + name: unquote(event_name), visitors: 5, events: 10, link_url: "https://two.com" @@ -1414,7 +1414,7 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do filters = Jason.encode!([ - [:is, "event:goal", [unquote(goal_name)]], + [:is, "event:goal", [unquote(event_name)]], [:is, "event:props:url", ["https://two.com"]] ])