2023-09-04 14:44:22 +03:00
|
|
|
defmodule PlausibleWeb.Live.GoalSettingsTest do
|
|
|
|
use PlausibleWeb.ConnCase, async: true
|
|
|
|
import Phoenix.LiveViewTest
|
|
|
|
import Plausible.Test.Support.HTML
|
|
|
|
|
|
|
|
describe "GET /:website/settings/goals" do
|
|
|
|
setup [:create_user, :log_in, :create_site]
|
|
|
|
|
2024-04-29 09:05:33 +03:00
|
|
|
@tag :ee_only
|
2023-09-04 14:44:22 +03:00
|
|
|
test "lists goals for the site and renders links", %{conn: conn, site: site} do
|
|
|
|
{:ok, [g1, g2, g3]} = setup_goals(site)
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
|
|
|
|
resp = html_response(conn, 200)
|
|
|
|
assert resp =~ "Define actions that you want your users to take"
|
2023-09-05 15:43:01 +03:00
|
|
|
assert resp =~ "compose Goals into Funnels"
|
2023-12-04 15:22:17 +03:00
|
|
|
assert resp =~ "/#{URI.encode_www_form(site.domain)}/settings/funnels"
|
2023-09-04 14:44:22 +03:00
|
|
|
assert element_exists?(resp, ~s|a[href="https://plausible.io/docs/goal-conversions"]|)
|
|
|
|
|
|
|
|
assert resp =~ to_string(g1)
|
|
|
|
assert resp =~ "Pageview"
|
|
|
|
assert resp =~ to_string(g2)
|
|
|
|
assert resp =~ "Custom Event"
|
|
|
|
assert resp =~ to_string(g3)
|
2023-10-05 12:54:18 +03:00
|
|
|
assert resp =~ "Revenue Goal"
|
2023-09-04 14:44:22 +03:00
|
|
|
end
|
|
|
|
|
2024-04-29 09:05:33 +03:00
|
|
|
@tag :ee_only
|
2024-02-12 12:43:54 +03:00
|
|
|
test "lists Revenue Goals with feature availability annotation if the plan does not cover them",
|
|
|
|
%{conn: conn, user: user, site: site} do
|
|
|
|
{:ok, [_, _, g3]} = setup_goals(site)
|
|
|
|
|
|
|
|
user
|
|
|
|
|> Plausible.Auth.User.end_trial()
|
|
|
|
|> Plausible.Repo.update!()
|
|
|
|
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
|
|
|
|
resp = html_response(conn, 200)
|
|
|
|
|
|
|
|
assert g3.currency
|
|
|
|
assert resp =~ to_string(g3)
|
|
|
|
assert resp =~ "Unlock Revenue Goals by upgrading to a business plan"
|
|
|
|
end
|
|
|
|
|
2023-09-04 14:44:22 +03:00
|
|
|
test "lists goals with delete actions", %{conn: conn, site: site} do
|
|
|
|
{:ok, goals} = setup_goals(site)
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
resp = html_response(conn, 200)
|
|
|
|
|
|
|
|
for g <- goals do
|
|
|
|
assert element_exists?(
|
|
|
|
resp,
|
|
|
|
~s/button[phx-click="delete-goal"][phx-value-goal-id=#{g.id}]#delete-goal-#{g.id}/
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
test "if no goals are present, a proper info is displayed", %{conn: conn, site: site} do
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
resp = html_response(conn, 200)
|
|
|
|
assert resp =~ "No goals configured for this site"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "if goals are present, no info about missing goals is displayed", %{
|
|
|
|
conn: conn,
|
|
|
|
site: site
|
|
|
|
} do
|
|
|
|
{:ok, _goals} = setup_goals(site)
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
resp = html_response(conn, 200)
|
|
|
|
refute resp =~ "No goals configured for this site"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "add goal button is rendered", %{conn: conn, site: site} do
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
resp = html_response(conn, 200)
|
2024-01-15 13:39:30 +03:00
|
|
|
assert element_exists?(resp, ~s/button#add-goal-button[x-data]/)
|
|
|
|
attr = text_of_attr(resp, ~s/button#add-goal-button/, "x-on:click")
|
|
|
|
assert attr =~ "open-modal"
|
|
|
|
assert attr =~ "goals-form-modal"
|
2023-09-04 14:44:22 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
test "search goals input is rendered", %{conn: conn, site: site} do
|
|
|
|
conn = get(conn, "/#{site.domain}/settings/goals")
|
|
|
|
resp = html_response(conn, 200)
|
|
|
|
assert element_exists?(resp, ~s/input[type="text"]#filter-text/)
|
|
|
|
assert element_exists?(resp, ~s/form[phx-change="filter"]#filter-form/)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "GoalSettings live view" do
|
|
|
|
setup [:create_user, :log_in, :create_site]
|
|
|
|
|
|
|
|
test "allows goal deletion", %{conn: conn, site: site} do
|
|
|
|
{:ok, [g1, g2 | _]} = setup_goals(site)
|
|
|
|
{lv, html} = get_liveview(conn, site, with_html?: true)
|
|
|
|
|
|
|
|
assert html =~ to_string(g1)
|
|
|
|
assert html =~ to_string(g2)
|
|
|
|
|
|
|
|
html = lv |> element(~s/button#delete-goal-#{g1.id}/) |> render_click()
|
|
|
|
|
|
|
|
refute html =~ to_string(g1)
|
|
|
|
assert html =~ to_string(g2)
|
|
|
|
|
|
|
|
html = get(conn, "/#{site.domain}/settings/goals") |> html_response(200)
|
|
|
|
|
|
|
|
refute html =~ to_string(g1)
|
|
|
|
assert html =~ to_string(g2)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "allows list filtering / search", %{conn: conn, site: site} do
|
|
|
|
{:ok, [g1, g2, g3]} = setup_goals(site)
|
|
|
|
{lv, html} = get_liveview(conn, site, with_html?: true)
|
|
|
|
|
|
|
|
assert html =~ to_string(g1)
|
|
|
|
assert html =~ to_string(g2)
|
|
|
|
assert html =~ to_string(g3)
|
|
|
|
|
|
|
|
html = type_into_search(lv, to_string(g3))
|
|
|
|
|
|
|
|
refute html =~ to_string(g1)
|
|
|
|
refute html =~ to_string(g2)
|
|
|
|
assert html =~ to_string(g3)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "allows resetting filter text via backspace icon", %{conn: conn, site: site} do
|
|
|
|
{:ok, [g1, g2, g3]} = setup_goals(site)
|
|
|
|
{lv, html} = get_liveview(conn, site, with_html?: true)
|
|
|
|
|
|
|
|
refute element_exists?(html, ~s/svg[phx-click="reset-filter-text"]#reset-filter/)
|
|
|
|
|
|
|
|
html = type_into_search(lv, to_string(g3))
|
|
|
|
|
|
|
|
assert element_exists?(html, ~s/svg[phx-click="reset-filter-text"]#reset-filter/)
|
|
|
|
|
|
|
|
html = lv |> element(~s/svg#reset-filter/) |> render_click()
|
|
|
|
|
|
|
|
assert html =~ to_string(g1)
|
|
|
|
assert html =~ to_string(g2)
|
|
|
|
assert html =~ to_string(g3)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "allows resetting filter text via no match link", %{conn: conn, site: site} do
|
|
|
|
{:ok, _goals} = setup_goals(site)
|
|
|
|
lv = get_liveview(conn, site)
|
|
|
|
html = type_into_search(lv, "Definitely this is not going to render any matches")
|
|
|
|
|
|
|
|
assert html =~ "No goals found for this site. Please refine or"
|
|
|
|
assert html =~ "reset your search"
|
|
|
|
|
|
|
|
assert element_exists?(html, ~s/a[phx-click="reset-filter-text"]#reset-filter-hint/)
|
|
|
|
html = lv |> element(~s/a#reset-filter-hint/) |> render_click()
|
|
|
|
|
|
|
|
refute html =~ "No goals found for this site. Please refine or"
|
|
|
|
end
|
|
|
|
|
2024-01-15 13:39:30 +03:00
|
|
|
test "Add Goal form view is rendered immediately, though hidden", %{conn: conn, site: site} do
|
2023-09-04 14:44:22 +03:00
|
|
|
{:ok, _goals} = setup_goals(site)
|
2024-01-15 13:39:30 +03:00
|
|
|
{_, html} = get_liveview(conn, site, with_html?: true)
|
2023-09-04 14:44:22 +03:00
|
|
|
|
2023-09-05 15:43:01 +03:00
|
|
|
assert html =~ "Add Goal for #{site.domain}"
|
2023-09-04 14:44:22 +03:00
|
|
|
|
|
|
|
assert element_exists?(
|
|
|
|
html,
|
2024-01-15 13:39:30 +03:00
|
|
|
~s/div#goals-form form[phx-submit="save-goal"]/
|
2023-09-04 14:44:22 +03:00
|
|
|
)
|
|
|
|
end
|
2024-05-10 12:48:27 +03:00
|
|
|
|
|
|
|
test "auto-configuring custom event goals", %{conn: conn, site: site} do
|
|
|
|
populate_stats(site, [
|
|
|
|
build(:event, name: "Signup"),
|
|
|
|
build(:event, name: "Newsletter Signup"),
|
|
|
|
build(:event, name: "Purchase")
|
|
|
|
])
|
|
|
|
|
|
|
|
autoconfigure_button_selector = ~s/button[phx-click="autoconfigure"]/
|
|
|
|
|
|
|
|
assert_suggested_event_name_count = fn html, number ->
|
|
|
|
assert text_of_element(html, autoconfigure_button_selector) =~
|
|
|
|
"found #{number} custom events from the last 6 months that are not yet configured as goals"
|
|
|
|
end
|
|
|
|
|
|
|
|
{lv, html} = get_liveview(conn, site, with_html?: true)
|
|
|
|
|
|
|
|
# At first, 3 event names are suggested
|
|
|
|
assert_suggested_event_name_count.(html, 3)
|
|
|
|
|
|
|
|
# Add one goal
|
|
|
|
lv
|
|
|
|
|> element("#goals-form form")
|
|
|
|
|> render_submit(%{goal: %{event_name: "Signup"}})
|
|
|
|
|
|
|
|
html = render(lv)
|
|
|
|
|
|
|
|
# Now two goals are suggested because one is already added
|
|
|
|
assert_suggested_event_name_count.(html, 2)
|
|
|
|
|
|
|
|
# Delete the goal
|
|
|
|
goal = Plausible.Repo.get_by(Plausible.Goal, site_id: site.id, event_name: "Signup")
|
|
|
|
html = lv |> element(~s/button#delete-goal-#{goal.id}/) |> render_click()
|
|
|
|
|
|
|
|
# Suggested event name count should be 3 again
|
|
|
|
assert_suggested_event_name_count.(html, 3)
|
|
|
|
|
|
|
|
# Autoconfigure all custom event goals
|
|
|
|
lv
|
|
|
|
|> element(autoconfigure_button_selector)
|
|
|
|
|> render_click()
|
|
|
|
|
|
|
|
html = render(lv)
|
|
|
|
|
|
|
|
# All possible goals exist - no suggestions anymore
|
|
|
|
refute html =~ "from the last 6 months"
|
|
|
|
end
|
2023-09-04 14:44:22 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
defp setup_goals(site) do
|
|
|
|
{:ok, g1} = Plausible.Goals.create(site, %{"page_path" => "/go/to/blog/**"})
|
2024-01-15 13:39:30 +03:00
|
|
|
{:ok, g2} = Plausible.Goals.create(site, %{"event_name" => "Register"})
|
2023-09-04 14:44:22 +03:00
|
|
|
{:ok, g3} = Plausible.Goals.create(site, %{"event_name" => "Purchase", "currency" => "EUR"})
|
|
|
|
{:ok, [g1, g2, g3]}
|
|
|
|
end
|
|
|
|
|
|
|
|
defp get_liveview(conn, site, opts \\ []) do
|
|
|
|
conn = assign(conn, :live_module, PlausibleWeb.Live.GoalSettings)
|
|
|
|
{:ok, lv, html} = live(conn, "/#{site.domain}/settings/goals")
|
|
|
|
|
|
|
|
if Keyword.get(opts, :with_html?) do
|
|
|
|
{lv, html}
|
|
|
|
else
|
|
|
|
lv
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp type_into_search(lv, text) do
|
|
|
|
lv
|
|
|
|
|> element("form#filter-form")
|
|
|
|
|> render_change(%{
|
|
|
|
"_target" => ["filter-text"],
|
|
|
|
"filter-text" => "#{text}"
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|