714 lines
20 KiB
Elixir
714 lines
20 KiB
Elixir
defmodule PlausibleWeb.Live.InstallationV2Test do
|
|
use PlausibleWeb.ConnCase, async: true
|
|
use Plausible
|
|
use Plausible.Test.Support.DNS
|
|
|
|
import Phoenix.LiveViewTest
|
|
import Plausible.Test.Support.HTML
|
|
import Plausible.Teams.Test
|
|
|
|
alias Plausible.Site.TrackerScriptConfiguration
|
|
|
|
@migration_guide_link "https://plausible.io/docs/script-update-guide"
|
|
|
|
setup [:create_user, :log_in, :create_site]
|
|
|
|
setup %{site: site} do
|
|
FunWithFlags.enable(:scriptv2, for_actor: site)
|
|
:ok
|
|
end
|
|
|
|
describe "GET /:domain/installationv2" do
|
|
@tag :ee_only
|
|
test "renders loading installation screen on EE", %{conn: conn, site: site} do
|
|
resp = get(conn, "/#{site.domain}/installationv2") |> html_response(200)
|
|
|
|
assert resp =~ "animate-spin"
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "no loading spinner, no GTM tab on CE", %{conn: conn, site: site} do
|
|
resp = get(conn, "/#{site.domain}/installationv2") |> html_response(200)
|
|
|
|
tabs_text = text_of_element(resp, "a[data-phx-link='patch']")
|
|
|
|
assert length(String.split(tabs_text)) == 3
|
|
|
|
assert tabs_text =~ "Script"
|
|
assert tabs_text =~ "WordPress"
|
|
assert tabs_text =~ "NPM"
|
|
|
|
refute resp =~ "animate-spin"
|
|
end
|
|
end
|
|
|
|
describe "LiveView" do
|
|
@tag :ee_only
|
|
test "detects installation type when mounted", %{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Verify WordPress installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "When ?type=wordpress URL parameter is supplied, detected type is unused", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=wordpress")
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Verify WordPress installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "When ?type=gtm URL parameter is supplied, detected type is unused", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=gtm")
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Verify Tag Manager installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "When ?type=npm URL parameter is supplied, detected type is unused", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=npm")
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Verify NPM installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "When ?type=manual URL parameter is supplied, detected type is unused", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=manual")
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Verify Script installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "allows switching between installation tabs (EE)", %{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
|
|
lv
|
|
|> element("a[href*=\"type=wordpress\"]")
|
|
|> render_click()
|
|
|
|
html = render(lv)
|
|
assert html =~ "Verify WordPress installation"
|
|
|
|
lv
|
|
|> element("a[href*=\"type=gtm\"]")
|
|
|> render_click()
|
|
|
|
html = render(lv)
|
|
assert html =~ "Verify Tag Manager installation"
|
|
|
|
lv
|
|
|> element("a[href*=\"type=npm\"]")
|
|
|> render_click()
|
|
|
|
html = render(lv)
|
|
assert html =~ "Verify NPM installation"
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "allows switching between installation tabs (CE)", %{conn: conn, site: site} do
|
|
{lv, _html} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
|
|
lv
|
|
|> element("a[href*=\"type=wordpress\"]")
|
|
|> render_click()
|
|
|
|
html = render(lv)
|
|
assert html =~ "Verify WordPress installation"
|
|
end
|
|
|
|
test "manual installations has script snippet with expected ID", %{conn: conn, site: site} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual&flow=review")
|
|
|
|
assert eventually(fn ->
|
|
html = render(lv)
|
|
{html =~ "Verify Script installation", html}
|
|
end)
|
|
|
|
html = render(lv)
|
|
config = Plausible.Repo.get_by!(TrackerScriptConfiguration, site_id: site.id)
|
|
assert html =~ "Privacy-friendly analytics by Plausible"
|
|
assert html =~ "/js/#{config.id}.js"
|
|
assert html =~ "async"
|
|
end
|
|
|
|
test "manual installation shows optional measurements", %{conn: conn, site: site} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual&flow=review")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
assert html =~ "Optional measurements"
|
|
assert html =~ "Outbound links"
|
|
assert html =~ "File downloads"
|
|
assert html =~ "Form submissions"
|
|
end
|
|
|
|
test "manual installation shows advanced options in disclosure", %{conn: conn, site: site} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual&flow=review")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
assert html =~ "Advanced options"
|
|
assert html =~ "Manual tagging"
|
|
assert html =~ "404 error pages"
|
|
assert html =~ "Hashed page paths"
|
|
assert html =~ "Custom properties"
|
|
assert html =~ "Ecommerce revenue"
|
|
end
|
|
|
|
test "toggling optional measurements updates tracker configuration", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual&flow=review")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
|
|
config = TrackerScriptConfiguration |> Plausible.Repo.get_by!(site_id: site.id)
|
|
assert config.outbound_links == true
|
|
assert config.file_downloads == true
|
|
assert config.form_submissions == true
|
|
|
|
lv
|
|
|> element("form[phx-submit='submit']")
|
|
|> render_submit(%{
|
|
"tracker_script_configuration" => %{
|
|
"installation_type" => "manual",
|
|
"outbound_links" => "false",
|
|
"file_downloads" => "true",
|
|
"form_submissions" => "true"
|
|
}
|
|
})
|
|
|
|
updated_config = TrackerScriptConfiguration |> Plausible.Repo.get_by!(site_id: site.id)
|
|
assert updated_config.outbound_links == false
|
|
assert updated_config.file_downloads == true
|
|
assert updated_config.form_submissions == true
|
|
end
|
|
|
|
on_ee do
|
|
for {type, expected_text} <- [
|
|
{"manual", "Verify Script installation"},
|
|
{"wordpress", "Verify WordPress installation"},
|
|
{"gtm", "Verify Tag Manager installation"},
|
|
{"npm", "Verify NPM installation"}
|
|
] do
|
|
test "submitting form with #{type} redirects to verification (EE)", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
{lv, _html} = get_lv(conn, site, "?type=#{unquote(type)}")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ unquote(expected_text)
|
|
|
|
lv
|
|
|> element("form[phx-submit='submit']")
|
|
|> render_submit(%{
|
|
"tracker_script_configuration" => %{
|
|
"installation_type" => unquote(type),
|
|
"outbound_links" => "true",
|
|
"file_downloads" => "true",
|
|
"form_submissions" => "true"
|
|
}
|
|
})
|
|
|
|
assert_redirect(
|
|
lv,
|
|
Routes.site_path(conn, :verification, site.domain,
|
|
flow: "provisioning",
|
|
installation_type: unquote(type)
|
|
)
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "submitting the form redirects to verification (CE)", %{conn: conn, site: site} do
|
|
{lv, _html} = get_lv(conn, site)
|
|
|
|
lv
|
|
|> element("form[phx-submit='submit']")
|
|
|> render_submit(%{
|
|
"tracker_script_configuration" => %{
|
|
"installation_type" => "manual",
|
|
"outbound_links" => "true",
|
|
"file_downloads" => "true",
|
|
"form_submissions" => "true"
|
|
}
|
|
})
|
|
|
|
assert_redirect(
|
|
lv,
|
|
Routes.site_path(conn, :verification, site.domain,
|
|
flow: "provisioning",
|
|
installation_type: "manual"
|
|
)
|
|
)
|
|
end
|
|
|
|
test "404 goal gets created regardless of user options", %{conn: conn, site: site} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
|
|
# Test with all options disabled
|
|
lv
|
|
|> element("form[phx-submit='submit']")
|
|
|> render_submit(%{
|
|
"tracker_script_configuration" => %{
|
|
"installation_type" => "manual",
|
|
"outbound_links" => "false",
|
|
"file_downloads" => "false",
|
|
"form_submissions" => "false"
|
|
}
|
|
})
|
|
|
|
# 404 goal should still be created
|
|
goals = Plausible.Goals.for_site(site)
|
|
assert Enum.any?(goals, &(&1.event_name == "404"))
|
|
end
|
|
|
|
test "submitting form with review flow redirects to verification with flow param", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _html} = get_lv(conn, site, "?type=manual&flow=review")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
|
|
lv
|
|
|> element("form[phx-submit='submit']")
|
|
|> render_submit(%{
|
|
"tracker_script_configuration" => %{
|
|
"installation_type" => "manual",
|
|
"outbound_links" => "true",
|
|
"file_downloads" => "true",
|
|
"form_submissions" => "true"
|
|
}
|
|
})
|
|
|
|
assert_redirect(
|
|
lv,
|
|
Routes.site_path(conn, :verification, site.domain,
|
|
flow: "review",
|
|
installation_type: "manual"
|
|
)
|
|
)
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "detected WordPress installation shows special message", %{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "We've detected your website is using WordPress"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "if ratelimit for detection is exceeded, does not make detection request and falls back to recommending manual installation",
|
|
%{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
|
|
# exceed the rate limit for site detection
|
|
Plausible.RateLimit.check_rate(
|
|
Plausible.RateLimit,
|
|
"site_detection:#{site.domain}",
|
|
:timer.minutes(60),
|
|
1,
|
|
100
|
|
)
|
|
|
|
# this won't be used: if it were used, the output would be different
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
|
|
refute text(html) =~ "We've detected your website is using WordPress"
|
|
assert text(html) =~ "Verify Script installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "detected GTM installation shows special message", %{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_gtm()
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Tag Manager installation"
|
|
|
|
assert text(html) =~ "We've detected your website is using Google Tag Manager"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "detected NPM installation shows npm tab", %{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
|
|
stub_detection_result(%{
|
|
"v1Detected" => false,
|
|
"gtmLikely" => false,
|
|
"npm" => true,
|
|
"wordpressLikely" => false,
|
|
"wordpressPlugin" => false
|
|
})
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify NPM installation"
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "shows v1 detection warning and migration guide link for manual installation", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual_with_v1()
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=manual")
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Your website is running an outdated version of the tracking script"
|
|
assert element_exists?(html, "a[href='#{@migration_guide_link}']")
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "shows v1 migration guide link for manual instructions", %{conn: conn, site: site} do
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert text(html) =~ "Still using the legacy snippet"
|
|
assert element_exists?(html, "a[href='#{@migration_guide_link}']")
|
|
end
|
|
|
|
test "does not render link to migrate guide on WordPress installation tab", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress_with_v1()
|
|
end
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=wordpress")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify WordPress installation"
|
|
refute element_exists?(html, "a[href='#{@migration_guide_link}']")
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "falls back to manual installation when detection fails at dns check level", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain, [])
|
|
|
|
ExUnit.CaptureLog.capture_log(fn ->
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
assert eventually(fn ->
|
|
html = render(lv)
|
|
# Should default to manual installation when detection returns {:error, _}
|
|
{html =~ "Verify Script installation", html}
|
|
end)
|
|
end)
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "falls back to manual installation when dns succeeds but detection fails", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_error()
|
|
|
|
ExUnit.CaptureLog.capture_log(fn ->
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
# Should default to manual installation when detection returns {:error, _}
|
|
assert html =~ "Verify Script installation"
|
|
end)
|
|
end
|
|
end
|
|
|
|
describe "Authorization" do
|
|
test "requires site access permissions", %{conn: conn} do
|
|
other_user = insert(:user)
|
|
other_site = new_site(owner: other_user)
|
|
|
|
assert_raise Ecto.NoResultsError, fn ->
|
|
get_lv(conn, other_site)
|
|
end
|
|
end
|
|
|
|
test "allows viewer access to installation page", %{conn: conn, user: user} do
|
|
site = new_site()
|
|
add_guest(site, user: user, role: :viewer)
|
|
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
end
|
|
|
|
test "allows editor access to installation page", %{conn: conn, user: user} do
|
|
site = new_site()
|
|
add_guest(site, user: user, role: :editor)
|
|
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
end
|
|
end
|
|
|
|
describe "URL Parameter Handling" do
|
|
test "falls back to manual installation when invalid installation type parameter supplied",
|
|
%{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _} = get_lv(conn, site, "?type=invalid")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
end
|
|
|
|
test "falls back to provisioning flow when invalid flow parameter supplied", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
on_ee do
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_manual()
|
|
end
|
|
|
|
{lv, _} = get_lv(conn, site, "?flow=invalid")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Script installation"
|
|
end
|
|
end
|
|
|
|
describe "Detection Result Combinations" do
|
|
@describetag :ee_only
|
|
|
|
test "When GTM + Wordpress detected, GTM takes precedence", %{conn: conn, site: site} do
|
|
stub_lookup_a_records(site.domain)
|
|
|
|
stub_detection_result(%{
|
|
"v1Detected" => false,
|
|
"gtmLikely" => true,
|
|
"wordpressLikely" => true,
|
|
"wordpressPlugin" => false
|
|
})
|
|
|
|
{lv, _} = get_lv(conn, site)
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify Tag Manager installation"
|
|
end
|
|
end
|
|
|
|
describe "Legacy Installations" do
|
|
@tag :ee_only
|
|
test "uses detected type in review flow when installation_type is nil", %{
|
|
conn: conn,
|
|
site: site
|
|
} do
|
|
_config =
|
|
PlausibleWeb.Tracker.get_or_create_tracker_script_configuration!(site, %{
|
|
installation_type: nil,
|
|
outbound_links: true,
|
|
file_downloads: false,
|
|
form_submissions: true
|
|
})
|
|
|
|
stub_lookup_a_records(site.domain)
|
|
stub_detection_wordpress()
|
|
|
|
{lv, _} = get_lv(conn, site, "?flow=review")
|
|
|
|
html = render_async(lv, 500)
|
|
assert html =~ "Verify WordPress installation"
|
|
end
|
|
end
|
|
|
|
defp stub_detection_manual do
|
|
stub_detection_result(%{
|
|
"v1Detected" => false,
|
|
"gtmLikely" => false,
|
|
"npm" => false,
|
|
"wordpressLikely" => false,
|
|
"wordpressPlugin" => false
|
|
})
|
|
end
|
|
|
|
defp stub_detection_wordpress do
|
|
stub_detection_result(%{
|
|
"v1Detected" => false,
|
|
"gtmLikely" => false,
|
|
"npm" => false,
|
|
"wordpressLikely" => true,
|
|
"wordpressPlugin" => false
|
|
})
|
|
end
|
|
|
|
defp stub_detection_gtm do
|
|
stub_detection_result(%{
|
|
"v1Detected" => false,
|
|
"gtmLikely" => true,
|
|
"npm" => false,
|
|
"wordpressLikely" => false,
|
|
"wordpressPlugin" => false
|
|
})
|
|
end
|
|
|
|
defp stub_detection_manual_with_v1 do
|
|
stub_detection_result(%{
|
|
"v1Detected" => true,
|
|
"gtmLikely" => false,
|
|
"npm" => false,
|
|
"wordpressLikely" => false,
|
|
"wordpressPlugin" => false
|
|
})
|
|
end
|
|
|
|
on_ee do
|
|
defp stub_detection_wordpress_with_v1 do
|
|
stub_detection_result(%{
|
|
"v1Detected" => true,
|
|
"gtmLikely" => false,
|
|
"npm" => false,
|
|
"wordpressLikely" => true,
|
|
"wordpressPlugin" => false
|
|
})
|
|
end
|
|
end
|
|
|
|
defp stub_detection_result(js_data) do
|
|
Req.Test.stub(:global, fn conn ->
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(200, Jason.encode!(%{"data" => Map.put(js_data, "completed", true)}))
|
|
end)
|
|
end
|
|
|
|
defp stub_detection_error do
|
|
Req.Test.stub(:global, fn conn ->
|
|
conn
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(
|
|
200,
|
|
Jason.encode!(%{"data" => %{"error" => %{"message" => "Simulated browser error"}}})
|
|
)
|
|
end)
|
|
end
|
|
|
|
defp get_lv(conn, site, qs \\ nil) do
|
|
{:ok, lv, html} = live(conn, "/#{site.domain}/installationv2#{qs}")
|
|
|
|
{lv, html}
|
|
end
|
|
end
|