diff --git a/assets/js/dashboard/email-reports-cta-banner.tsx b/assets/js/dashboard/email-reports-cta-banner.tsx
new file mode 100644
index 000000000000..8defbd306b23
--- /dev/null
+++ b/assets/js/dashboard/email-reports-cta-banner.tsx
@@ -0,0 +1,124 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { XMarkIcon } from '@heroicons/react/24/outline'
+import { useSiteContext } from './site-context'
+import { useCurrentVisitorsContext } from './current-visitors-context'
+
+type CTAStorageState = 'pending' | 'visible'
+
+function getStorageKey(domain: string) {
+ return `email_reports_cta_${domain}`
+}
+
+// CTA for configuring weekly email reports
+//
+// Renders only once, as soon as the first pageview lands. This can happen:
+//
+// 1. Automatically, when the dashboard stays open -- relying on the value
+// of current-visitors changing to something other than 0.
+//
+// 2. Dashboard is refreshed and showing data for the very first time.
+//
+// Case 2 is the tricky one. By the time of the refresh, `site.statsBegin`
+// is already set, so that value alone can't distinguish "stats just
+// started" from "this site has always had stats".
+//
+// The sessionStorage entry closes that gap -- it's stamped 'pending' the
+// moment stats are still absent, so a later reload can still recognize the
+// transition. It is only ever stamped while stats are absent, so established
+// sites never pick it up and can't retrigger the CTA.
+//
+// Once shown, the same entry is stamped 'visible', so a refresh mid-display
+// resumes the CTA instead of re-deciding from scratch -- but only for three
+// seconds -- past that, the sessionStorage entry clears itself out and a
+// refresh won't bring the CTA back.
+export function EmailReportsCTABanner() {
+ const site = useSiteContext()
+ const currentVisitors = useCurrentVisitorsContext()
+ const hasStats = !!site.statsBegin
+ const storageKey = getStorageKey(site.domain)
+
+ const hasTriggeredRef = useRef(false)
+ const [visible, setVisible] = useState(false)
+
+ useEffect(() => {
+ if (!hasStats && sessionStorage.getItem(storageKey) !== 'visible') {
+ const state: CTAStorageState = 'pending'
+ sessionStorage.setItem(storageKey, state)
+ }
+ }, [hasStats, storageKey])
+
+ useEffect(() => {
+ if (hasTriggeredRef.current) {
+ return
+ }
+
+ const storedState = sessionStorage.getItem(storageKey)
+
+ if (storedState === 'visible') {
+ hasTriggeredRef.current = true
+ setVisible(true)
+ return
+ }
+
+ const firstPageviewJustLanded = hasStats
+ ? storedState === 'pending'
+ : !!currentVisitors
+
+ if (!firstPageviewJustLanded) {
+ return
+ }
+
+ hasTriggeredRef.current = true
+ const state: CTAStorageState = 'visible'
+ sessionStorage.setItem(storageKey, state)
+ setVisible(true)
+ }, [hasStats, currentVisitors, storageKey])
+
+ useEffect(() => {
+ if (!visible) {
+ return
+ }
+
+ const timeout = setTimeout(() => {
+ sessionStorage.removeItem(storageKey)
+ }, 3000)
+
+ return () => clearTimeout(timeout)
+ }, [visible, storageKey])
+
+ if (!visible) {
+ return null
+ }
+
+ function dismiss() {
+ sessionStorage.removeItem(storageKey)
+ setVisible(false)
+ }
+
+ return (
+
-
-
<%= if Plausible.Teams.locked?(@site.team) do %>
+ <%= if @verify_installation? do %>
+ {live_render(@conn, PlausibleWeb.Live.Verification,
+ id: "live-verification",
+ session: @verification_session
+ )}
+ <% end %>
<%= if ee?() && !@conn.assigns[:current_user] && @conn.assigns[:demo] do %>
diff --git a/test/plausible/installation_support/verification/checks_test.exs b/test/plausible/installation_support/verification/checks_test.exs
index a0b7ef39a8dd..b9e0bde8e134 100644
--- a/test/plausible/installation_support/verification/checks_test.exs
+++ b/test/plausible/installation_support/verification/checks_test.exs
@@ -13,6 +13,11 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
@expected_domain "example.com"
@url_to_verify "https://#{@expected_domain}"
+ @verify_manually_url "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ @verify_manually_inline_link %{
+ text: "verify your installation manually",
+ href: @verify_manually_url
+ }
describe "URL check" do
test "returns error when DNS check fails with domain not found error, offers custom URL input" do
@@ -22,14 +27,13 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
ok?: false,
data: %{offer_custom_url_input: true},
errors: [
- ^any(:string, ~r/We couldn't find your website at #{@url_to_verify}$/)
+ ^any(:string, ~r/We couldn't reach #{@url_to_verify}$/)
],
recommendations: [
%{
text:
- "Please check that the domain you entered is correct and reachable publicly. If it's intentionally private, you'll need to verify that Plausible works manually",
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ "Check that the URL is correct and publicly accessible. If your site is intentionally private, you can verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -49,14 +53,13 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
ok?: false,
data: %{offer_custom_url_input: true},
errors: [
- ^any(:string, ~r/We couldn't find your website at #{url_to_verify}$/)
+ ^any(:string, ~r/We couldn't reach #{url_to_verify}$/)
],
recommendations: [
%{
text:
- "Please check that the domain you entered is correct and reachable publicly. If it's intentionally private, you'll need to verify that Plausible works manually",
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ "Check that the URL is correct and publicly accessible. If your site is intentionally private, you can verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -94,13 +97,13 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
for {installation_type, expected_recommendation} <- [
{"wordpress",
- "Please check that you've installed the WordPress plugin correctly, or verify your installation manually"},
+ "Check you've installed the WordPress plugin correctly, or verify your installation manually"},
{"gtm",
- "Please check that you've entered the ID in the GTM template correctly, or verify your installation manually"},
+ "Check you've entered the ID in the GTM template correctly, or verify your installation manually"},
{"npm",
- "Please check that you've initialized Plausible with the correct domain, or verify your installation manually"},
+ "Check you've initialized Plausible with the correct domain, or verify your installation manually"},
{"manual",
- "Please check that the snippet on your site matches the installation instructions exactly, or verify your installation manually"}
+ "Check that the snippet on your site matches the one shown in the installation instructions, or verify your installation manually"}
] do
test "returns error when test event domain doesn't match the expected domain, with recommendation for installation type: #{installation_type}" do
verification_stub =
@@ -119,12 +122,11 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
- errors: ["Plausible test event is not for this site"],
+ errors: ["Your Plausible snippet is configured for a different domain"],
recommendations: [
%{
text: unquote(expected_recommendation),
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -154,11 +156,16 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
- errors: [^any(:string, ~r/.*proxy.*/)],
+ errors: [^any(:string, ~r/.*proxied.*/)],
recommendations: [
%{
text: ^any(:string, ~r/.*proxied.*/),
- url: "https://plausible.io/docs/proxy/introduction"
+ inline_links: [
+ %{
+ text: "Learn more",
+ href: "https://plausible.io/docs/proxy/introduction"
+ }
+ ]
}
]
} =
@@ -187,9 +194,9 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
errors: [^any(:string, ~r/.*couldn't verify.*/)],
recommendations: [
%{
- text: ^any(:string, ~r/.*try verifying again.*/),
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ text:
+ "Please try verifying again in a few minutes, or verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -213,9 +220,8 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
recommendations: [
%{
text:
- "Please make sure you've copied the snippet to the head of your site, or verify your installation manually",
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ "Make sure you've copied the snippet to the head of your site, or verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -236,14 +242,19 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
errors: [
- "We encountered an issue with your site's Content Security Policy (CSP)"
+ "Your site's Content Security Policy (CSP) is blocking Plausible"
],
recommendations: [
%{
text:
- "Please add plausible.io domain specifically to the allowed list of domains in your site's CSP",
- url:
- "https://plausible.io/docs/troubleshoot-integration#does-your-site-use-a-content-security-policy-csp"
+ "Add plausible.io to the list of allowed domains in your site's Content Security Policy to allow Plausible to collect analytics. Learn more",
+ inline_links: [
+ %{
+ text: "Learn more",
+ href:
+ "https://plausible.io/docs/troubleshoot-integration#does-your-site-use-a-content-security-policy-csp"
+ }
+ ]
}
]
} =
@@ -261,15 +272,12 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
data: %{offer_custom_url_input: true},
- errors: [
- "We couldn't verify your website at https://example.com"
- ],
+ errors: ["We couldn't verify https://example.com"],
recommendations: [
%{
text:
- "Accessing the website resulted in a network error. Please verify your installation manually",
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ "We encountered a network error while trying to access your website. You can verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -291,15 +299,12 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
data: %{offer_custom_url_input: true},
- errors: [
- "We couldn't verify your website at https://example.com"
- ],
+ errors: ["We couldn't verify https://example.com"],
recommendations: [
%{
text:
- "Accessing the website resulted in an unexpected status code 403. Please check for anything that might be blocking us from reaching your site, like a firewall, authentication requirements, or CDN rules. If you'd prefer, you can skip this and verify your installation manually",
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ "Accessing your website returned an unexpected status code (403). Check for anything that might be blocking our access to your site, such as a firewall, authentication requirements, or CDN rules. You can also verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -309,13 +314,13 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
for {installation_type, expected_recommendation} <- [
{"wordpress",
- "Please make sure you've enabled the plugin, or verify your installation manually"},
+ "Make sure you've enabled the WordPress plugin, or verify your installation manually"},
{"gtm",
- "Please make sure you've configured the GTM template correctly, or verify your installation manually"},
+ "Make sure you've configured the GTM template correctly, or verify your installation manually"},
{"npm",
- "Please make sure you've initialized Plausible on your site, or verify your installation manually"},
+ "Make sure you've initialized Plausible on your site, or verify your installation manually"},
{"manual",
- "Please make sure you've copied the snippet to the head of your site, or verify your installation manually"}
+ "Make sure you've copied the snippet to the head of your site, or verify your installation manually"}
] do
test "returns error \"We couldn't detect Plausible on your site\" when plausible_is_on_window is false (with best guess recommendation for installation type: #{installation_type})" do
verification_stub =
@@ -334,8 +339,7 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
recommendations: [
%{
text: unquote(expected_recommendation),
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -363,8 +367,7 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
recommendations: [
%{
text: unquote(expected_recommendation),
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ inline_links: [^@verify_manually_inline_link]
}
]
} =
@@ -426,8 +429,13 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
recommendations: [
%{
text: ^any(:string, ~r/.*cache.*/),
- url:
- "https://plausible.io/docs/troubleshoot-integration#have-you-cleared-the-cache-of-your-site"
+ inline_links: [
+ %{
+ text: "Learn more",
+ href:
+ "https://plausible.io/docs/troubleshoot-integration#have-you-cleared-the-cache-of-your-site"
+ }
+ ]
}
]
} = run_checks(verification_stub) |> Checks.interpret_diagnostics()
@@ -484,12 +492,12 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
- errors: [^any(:string, ~r/.*temporary service error.*/)],
+ errors: [^any(:string, ~r/.*temporarily unavailable.*/)],
recommendations: [
%{
- text: ^any(:string, ~r/.*in a few minutes.*/),
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ text:
+ "Please try again in a few minutes or verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} = Checks.interpret_diagnostics(state)
@@ -514,12 +522,12 @@ defmodule Plausible.InstallationSupport.Verification.ChecksTest do
assert_matches %Result{
ok?: false,
- errors: [^any(:string, ~r/.*temporary service error.*/)],
+ errors: [^any(:string, ~r/.*temporarily unavailable.*/)],
recommendations: [
%{
- text: ^any(:string, ~r/.*in a few minutes.*/),
- url:
- "https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"
+ text:
+ "Please try again in a few minutes or verify your installation manually",
+ inline_links: [^@verify_manually_inline_link]
}
]
} = Checks.interpret_diagnostics(state)
diff --git a/test/plausible/installation_support/verification/diagnostics_test.exs b/test/plausible/installation_support/verification/diagnostics_test.exs
new file mode 100644
index 000000000000..bead8dfa1df0
--- /dev/null
+++ b/test/plausible/installation_support/verification/diagnostics_test.exs
@@ -0,0 +1,46 @@
+defmodule Plausible.InstallationSupport.Verification.DiagnosticsTest do
+ use ExUnit.Case, async: true
+
+ alias Plausible.InstallationSupport.Verification.Diagnostics.Error
+
+ describe "Error.new!/1" do
+ test "accepts a recommendation whose inline_links text appears exactly once" do
+ assert %Error{} =
+ Error.new!(%{
+ message: "Something went wrong",
+ recommendation: "Check the docs for more info",
+ inline_links: [%{text: "docs", href: "https://plausible.io/docs"}]
+ })
+ end
+
+ test "raises when inline_links text isn't found in the recommendation" do
+ assert_raise ArgumentError, ~r/must appear exactly once/, fn ->
+ Error.new!(%{
+ message: "Something went wrong",
+ recommendation: "Check the manual for more info",
+ inline_links: [%{text: "docs", href: "https://plausible.io/docs"}]
+ })
+ end
+ end
+
+ test "raises when inline_links text appears more than once in the recommendation" do
+ assert_raise ArgumentError, ~r/must appear exactly once/, fn ->
+ Error.new!(%{
+ message: "Something went wrong",
+ recommendation: "Check the docs, or check the docs again",
+ inline_links: [%{text: "the docs", href: "https://plausible.io/docs"}]
+ })
+ end
+ end
+
+ test "raises when inline_links href doesn't point at plausible.io" do
+ assert_raise ArgumentError, ~r/must start with/, fn ->
+ Error.new!(%{
+ message: "Something went wrong",
+ recommendation: "Check the docs for more info",
+ inline_links: [%{text: "docs", href: "https://example.com/docs"}]
+ })
+ end
+ end
+ end
+end
diff --git a/test/plausible_web/controllers/site_controller_test.exs b/test/plausible_web/controllers/site_controller_test.exs
index bb76d271a853..22407b15979e 100644
--- a/test/plausible_web/controllers/site_controller_test.exs
+++ b/test/plausible_web/controllers/site_controller_test.exs
@@ -362,7 +362,7 @@ defmodule PlausibleWeb.SiteControllerTest do
})
assert redirected_to(conn) ==
- "/#{URI.encode_www_form("éxample.com")}/installation?site_created=true&flow="
+ "/#{URI.encode_www_form("éxample.com")}/installation?flow="
assert site = Repo.get_by(Plausible.Site, domain: "éxample.com")
assert site.timezone == "Europe/London"
@@ -480,7 +480,7 @@ defmodule PlausibleWeb.SiteControllerTest do
}
})
- assert redirected_to(conn) == "/example.com/installation?site_created=true&flow="
+ assert redirected_to(conn) == "/example.com/installation?flow="
assert Repo.get_by(Plausible.Site, domain: "example.com")
end
@@ -501,7 +501,7 @@ defmodule PlausibleWeb.SiteControllerTest do
}
})
- assert redirected_to(conn) == "/example.com/installation?site_created=true&flow="
+ assert redirected_to(conn) == "/example.com/installation?flow="
assert Plausible.Teams.Billing.site_usage(team) == 3
end
@@ -515,7 +515,7 @@ defmodule PlausibleWeb.SiteControllerTest do
}
})
- assert redirected_to(conn) == "/example.com/installation?site_created=true&flow="
+ assert redirected_to(conn) == "/example.com/installation?flow="
assert Repo.get_by(Plausible.Site, domain: "example.com")
end
end
@@ -555,7 +555,7 @@ defmodule PlausibleWeb.SiteControllerTest do
})
assert redirected_to(conn) ==
- "/example.com%2Fsome_blog_site/installation?site_created=true&flow="
+ "/example.com%2Fsome_blog_site/installation?flow="
end
test "renders form again when it is a duplicate domain", %{conn: conn} do
@@ -618,7 +618,7 @@ defmodule PlausibleWeb.SiteControllerTest do
})
assert redirected_to(conn) ==
- "/example.com/installation?site_created=true&flow="
+ "/example.com/installation?flow="
end
for role <- [:owner, :admin, :editor] do
diff --git a/test/plausible_web/controllers/stats_controller_test.exs b/test/plausible_web/controllers/stats_controller_test.exs
index 38155954a91d..fab0eef0ba75 100644
--- a/test/plausible_web/controllers/stats_controller_test.exs
+++ b/test/plausible_web/controllers/stats_controller_test.exs
@@ -104,28 +104,28 @@ defmodule PlausibleWeb.StatsControllerTest do
assert resp =~ "Getting started"
end
- test "public site - redirect to /login when no stats because verification requires it", %{
- conn: conn
- } do
+ test "public site - shows an empty dashboard without stats (no verification banner)",
+ %{
+ conn: conn
+ } do
new_site(domain: "some-other-public-site.io", public: true)
- conn = get(conn, conn |> get("/some-other-public-site.io") |> redirected_to())
+ resp = get(conn, "/some-other-public-site.io") |> html_response(200)
- assert redirected_to(conn) ==
- Routes.auth_path(conn, :login_form,
- return_to: "/some-other-public-site.io/verification"
- )
+ refute resp =~ "Verifying your installation"
end
- test "public site - no stats with skip_to_dashboard", %{
- conn: conn
- } do
+ test "public site - anonymous visitors never see the verification banner, even with the param",
+ %{
+ conn: conn
+ } do
new_site(domain: "some-other-public-site.io", public: true)
- conn = get(conn, "/some-other-public-site.io?skip_to_dashboard=true")
- resp = html_response(conn, 200)
+ resp =
+ get(conn, "/some-other-public-site.io?verify_installation=true") |> html_response(200)
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
+ refute resp =~ "Verifying your installation"
end
test "can not view stats of a private website", %{conn: conn} do
@@ -147,15 +147,18 @@ defmodule PlausibleWeb.StatsControllerTest do
assert text_of_attr(resp, @react_container, "data-current-user-id") == "#{user.id}"
end
- test "can view stats of a website I've created, enforcing pageviews check skip", %{
- conn: conn,
- site: site
- } do
- resp = conn |> get(conn |> get("/" <> site.domain) |> redirected_to()) |> html_response(200)
- refute text_of_attr(resp, @react_container, "data-logged-in") == "true"
+ test "can view stats of a website I've created; verification banner only shows with the explicit param",
+ %{
+ conn: conn,
+ site: site
+ } do
+ resp = get(conn, "/" <> site.domain) |> html_response(200)
+ assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
+ refute resp =~ "Verifying your installation"
- resp = conn |> get("/" <> site.domain <> "?skip_to_dashboard=true") |> html_response(200)
+ resp = conn |> get("/" <> site.domain <> "?verify_installation=true") |> html_response(200)
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
+ assert resp =~ "Verifying your installation"
end
on_ee do
@@ -334,9 +337,9 @@ defmodule PlausibleWeb.StatsControllerTest do
end
test "does not show CRM link to the site", %{conn: conn, site: site} do
- conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
+ resp = get(conn, "/" <> site.domain) |> html_response(200)
- refute html_response(conn, 200) =~ "/cs/sites"
+ refute resp =~ "/cs/sites"
end
test "all segments (personal or site) are stuffed into dataset, with their associated owner_id and owner_name",
@@ -390,8 +393,8 @@ defmodule PlausibleWeb.StatsControllerTest do
test "can enter verification when site is without stats", %{conn: conn} do
site = new_site()
- conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
- assert html_response(conn, 200) =~ "Verifying your installation"
+ resp = get(conn, "/#{site.domain}?verify_installation=true") |> html_response(200)
+ assert resp =~ "Verifying your installation"
end
test "can view a private locked dashboard with stats", %{conn: conn} do
@@ -410,8 +413,8 @@ defmodule PlausibleWeb.StatsControllerTest do
site = new_site(owner: user)
site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
- conn = get(conn, conn |> get("/#{site.domain}") |> redirected_to())
- assert html_response(conn, 200) =~ "Verifying your installation"
+ resp = get(conn, "/#{site.domain}?verify_installation=true") |> html_response(200)
+ assert resp =~ "Verifying your installation"
end
test "can view a locked public dashboard", %{conn: conn} do
@@ -427,9 +430,9 @@ defmodule PlausibleWeb.StatsControllerTest do
on_ee do
test "shows CRM link to the site", %{conn: conn} do
site = new_site()
- conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
+ resp = get(conn, "/" <> site.domain) |> html_response(200)
- assert html_response(conn, 200) =~
+ assert resp =~
Routes.customer_support_site_path(PlausibleWeb.Endpoint, :show, site.id)
end
end
diff --git a/test/plausible_web/live/components/verification_banner_test.exs b/test/plausible_web/live/components/verification_banner_test.exs
new file mode 100644
index 000000000000..0ecdf1bc8a58
--- /dev/null
+++ b/test/plausible_web/live/components/verification_banner_test.exs
@@ -0,0 +1,243 @@
+defmodule PlausibleWeb.Live.Components.VerificationBannerTest do
+ use PlausibleWeb.ConnCase, async: true
+
+ on_ee do
+ import Phoenix.LiveViewTest, only: [render_component: 2]
+
+ alias Plausible.InstallationSupport.{State, Verification}
+
+ @moduletag :capture_log
+
+ @component PlausibleWeb.Live.Components.VerificationBanner
+ @progress ~s|#verification-ui p#progress|
+
+ @loading_spinner ~s|#verification-ui svg.animate-spin|
+ @check_circle ~s|#verification-ui #check-circle|
+ @recommendations ~s|#recommendation|
+ @super_admin_report ~s|#super-admin-report|
+
+ test "renders initial state" do
+ html = render_component(@component, domain: "example.com")
+ assert element_exists?(html, @progress)
+
+ assert text_of_element(html, @progress) ==
+ "We're visiting your site to ensure that everything is working..."
+
+ assert element_exists?(html, @loading_spinner)
+ refute element_exists?(html, @recommendations)
+ refute element_exists?(html, @check_circle)
+ refute element_exists?(html, @super_admin_report)
+ end
+
+ test "renders failed state without progress spinner" do
+ html = render_component(@component, domain: "example.com", success?: false, finished?: true)
+ refute element_exists?(html, @loading_spinner)
+ refute element_exists?(html, @check_circle)
+ refute element_exists?(html, @recommendations)
+ assert html =~ "We couldn't verify your installation"
+ end
+
+ test "renders diagnostic interpretation with inline verify link and standalone review-installation sentence" do
+ interpretation =
+ Verification.Checks.interpret_diagnostics(%State{
+ url: "https://example.com",
+ data_domain: "example.com",
+ diagnostics: %Verification.Diagnostics{service_error: %{code: :domain_not_found}}
+ })
+
+ html =
+ render_component(@component,
+ domain: "example.com",
+ success?: false,
+ finished?: true,
+ interpretation: interpretation
+ )
+
+ assert [recommendation] = html |> find(@recommendations) |> Enum.map(&text/1)
+ assert recommendation =~ "Check that the URL is correct and publicly accessible"
+ assert recommendation =~ "verify your installation manually"
+ refute recommendation =~ "review your installation"
+ assert recommendation =~ "See your installation instructions again here"
+
+ assert element_exists?(
+ html,
+ ~s|#recommendation a[href="https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"]|
+ )
+
+ assert element_exists?(
+ html,
+ ~s|#recommendation a[href="/example.com/installation?flow="]|
+ )
+
+ refute element_exists?(html, @super_admin_report)
+ end
+
+ test "renders inline verify-manually link when the recommendation mentions it (no custom URL retry)" do
+ interpretation =
+ Verification.Checks.interpret_diagnostics(%State{
+ url: "https://example.com",
+ data_domain: "example.com",
+ diagnostics: %Verification.Diagnostics{
+ plausible_is_on_window: false,
+ selected_installation_type: "manual"
+ }
+ })
+
+ refute Map.get(interpretation.data || %{}, :offer_custom_url_input) == true
+
+ html =
+ render_component(@component,
+ domain: "example.com",
+ success?: false,
+ finished?: true,
+ interpretation: interpretation
+ )
+
+ assert [recommendation] = html |> find(@recommendations) |> Enum.map(&text/1)
+ assert recommendation =~ "Make sure you've copied the snippet"
+ assert recommendation =~ "verify your installation manually"
+ refute recommendation =~ "review your installation"
+ refute recommendation =~ "Learn more"
+ refute recommendation =~ "See your installation instructions again here"
+
+ assert element_exists?(
+ html,
+ ~s|#recommendation a[href="https://plausible.io/docs/troubleshoot-integration#how-to-manually-check-your-integration"]|
+ )
+
+ refute element_exists?(html, ~s|#recommendation a[href^="/example.com/installation"]|)
+ end
+
+ test "renders super-admin report" do
+ state = %State{
+ url: "https://example.com",
+ data_domain: "example.com",
+ diagnostics: %Verification.Diagnostics{}
+ }
+
+ interpretation = Verification.Checks.interpret_diagnostics(state)
+
+ html =
+ render_component(@component,
+ domain: "example.com",
+ success?: false,
+ finished?: true,
+ interpretation: interpretation,
+ verification_state: state,
+ super_admin?: true
+ )
+
+ assert element_exists?(html, @super_admin_report)
+ assert text_of_element(html, @super_admin_report) =~ "Plausible is on window: nil"
+ end
+
+ test "hides pulsating circle when finished, shows check circle" do
+ html =
+ render_component(@component,
+ domain: "example.com",
+ success?: true,
+ finished?: true
+ )
+
+ refute element_exists?(html, @loading_spinner)
+ assert element_exists?(html, @check_circle)
+ end
+
+ test "renders a progress message" do
+ html = render_component(@component, domain: "example.com", message: "Arbitrary message")
+
+ assert text_of_element(html, @progress) == "Arbitrary message..."
+ end
+
+ test "renders contact link on >=3 attempts" do
+ html = render_component(@component, domain: "example.com", attempts: 2, finished?: true)
+ refute html =~ "Need help?"
+ refute element_exists?(html, ~s|a[href="https://plausible.io/contact"]|)
+
+ html = render_component(@component, domain: "example.com", attempts: 3, finished?: true)
+ assert html =~ "Need help?"
+ assert element_exists?(html, ~s|a[href="https://plausible.io/contact"]|)
+ end
+
+ test "renders a Try another URL ghost button when a custom URL retry is offered" do
+ interpretation =
+ Verification.Checks.interpret_diagnostics(%State{
+ url: "example.com",
+ diagnostics: %Verification.Diagnostics{
+ plausible_is_on_window: false,
+ plausible_is_initialized: false,
+ service_error: %{code: :domain_not_found}
+ }
+ })
+
+ assert interpretation.data.offer_custom_url_input == true
+
+ html =
+ render_component(@component,
+ domain: "example.com",
+ finished?: true,
+ success?: false,
+ interpretation: interpretation
+ )
+
+ assert text_of_element(html, "#verify-custom-url-link") =~ "Try another URL"
+ assert element_exists?(html, ~s|a#verify-custom-url-link[phx-click="show-custom-url-form"]|)
+ refute html =~ "Review installation"
+ end
+
+ test "renders the custom URL input inline, replacing Check again with the Verify URL submit button, and hides the secondary action" do
+ interpretation =
+ Verification.Checks.interpret_diagnostics(%State{
+ url: "example.com",
+ diagnostics: %Verification.Diagnostics{
+ plausible_is_on_window: false,
+ plausible_is_initialized: false,
+ service_error: %{code: :domain_not_found}
+ }
+ })
+
+ html =
+ render_component(@component,
+ domain: "example.com",
+ finished?: true,
+ success?: false,
+ interpretation: interpretation,
+ custom_url_input?: true
+ )
+
+ refute element_exists?(html, "#verify-custom-url-link")
+ refute element_exists?(html, ~s|a[phx-click="retry"]|)
+ refute html =~ "Review installation"
+
+ assert text_of_element(html, ~s|form[phx-submit="verify-custom-url"] button[type="submit"]|) =~
+ "Verify URL"
+
+ assert element_exists?(
+ html,
+ ~s|form[phx-submit="verify-custom-url"] input[name="custom_url"]|
+ )
+
+ assert text_of_attr(html, ~s|form[phx-submit="verify-custom-url"] input|, "value") =~
+ "https://example.com"
+ end
+
+ test "offers a Review installation ghost button on failure by default" do
+ html =
+ render_component(@component,
+ domain: "example.com",
+ success?: false,
+ finished?: true,
+ flow: PlausibleWeb.Flows.review()
+ )
+
+ refute element_exists?(html, ~s|a[href="/example.com/settings/general"]|)
+
+ assert element_exists?(
+ html,
+ ~s|a[href="/example.com/installation?flow=review"]|
+ )
+
+ assert html =~ "Review installation"
+ end
+ end
+end
diff --git a/test/plausible_web/live/components/verification_test.exs b/test/plausible_web/live/components/verification_test.exs
deleted file mode 100644
index 2645de32cc4e..000000000000
--- a/test/plausible_web/live/components/verification_test.exs
+++ /dev/null
@@ -1,162 +0,0 @@
-defmodule PlausibleWeb.Live.Components.VerificationTest do
- use PlausibleWeb.ConnCase, async: true
-
- on_ee do
- import Phoenix.LiveViewTest, only: [render_component: 2]
-
- alias Plausible.InstallationSupport.{State, Verification}
-
- @moduletag :capture_log
-
- @component PlausibleWeb.Live.Components.Verification
- @progress ~s|#verification-ui p#progress|
-
- @pulsating_circle ~s|div#verification-ui div.pulsating-circle|
- @check_circle ~s|div#verification-ui #check-circle|
- @error_circle ~s|div#verification-ui #error-circle|
- @recommendations ~s|#recommendation|
- @super_admin_report ~s|#super-admin-report|
-
- test "renders initial state" do
- html = render_component(@component, domain: "example.com")
- assert element_exists?(html, @progress)
-
- assert text_of_element(html, @progress) ==
- "We're visiting your site to ensure that everything is working"
-
- assert element_exists?(html, @pulsating_circle)
- refute class_of_element(html, @pulsating_circle) =~ "hidden"
- refute element_exists?(html, @recommendations)
- refute element_exists?(html, @check_circle)
- refute element_exists?(html, @super_admin_report)
- end
-
- test "renders error badge on error" do
- html = render_component(@component, domain: "example.com", success?: false, finished?: true)
- refute element_exists?(html, @pulsating_circle)
- refute element_exists?(html, @check_circle)
- refute element_exists?(html, @recommendations)
- assert element_exists?(html, @error_circle)
- end
-
- test "renders diagnostic interpretation" do
- interpretation =
- Verification.Checks.interpret_diagnostics(%State{
- url: "https://example.com",
- data_domain: "example.com",
- diagnostics: %Verification.Diagnostics{service_error: %{code: :domain_not_found}}
- })
-
- html =
- render_component(@component,
- domain: "example.com",
- success?: false,
- finished?: true,
- interpretation: interpretation
- )
-
- assert [recommendation] = html |> find(@recommendations) |> Enum.map(&text/1)
- assert recommendation =~ "check that the domain you entered is correct"
-
- refute element_exists?(html, @super_admin_report)
- end
-
- test "renders super-admin report" do
- state = %State{
- url: "https://example.com",
- data_domain: "example.com",
- diagnostics: %Verification.Diagnostics{}
- }
-
- interpretation = Verification.Checks.interpret_diagnostics(state)
-
- html =
- render_component(@component,
- domain: "example.com",
- success?: false,
- finished?: true,
- interpretation: interpretation,
- verification_state: state,
- super_admin?: true
- )
-
- assert element_exists?(html, @super_admin_report)
- assert text_of_element(html, @super_admin_report) =~ "Plausible is on window: nil"
- end
-
- test "hides pulsating circle when finished, shows check circle" do
- html =
- render_component(@component,
- domain: "example.com",
- success?: true,
- finished?: true
- )
-
- refute element_exists?(html, @pulsating_circle)
- assert element_exists?(html, @check_circle)
- end
-
- test "renders a progress message" do
- html = render_component(@component, domain: "example.com", message: "Arbitrary message")
-
- assert text_of_element(html, @progress) == "Arbitrary message"
- end
-
- test "renders contact link on >3 attempts" do
- html = render_component(@component, domain: "example.com", attempts: 2, finished?: true)
- refute html =~ "Need further help with your installation?"
- refute element_exists?(html, ~s|a[href="https://plausible.io/contact"]|)
-
- html = render_component(@component, domain: "example.com", attempts: 3, finished?: true)
- assert html =~ "Need further help with your installation?"
- assert element_exists?(html, ~s|a[href="https://plausible.io/contact"]|)
- end
-
- test "renders link to verify installation at a different URL" do
- interpretation =
- Verification.Checks.interpret_diagnostics(%State{
- url: "example.com",
- diagnostics: %Verification.Diagnostics{
- plausible_is_on_window: false,
- plausible_is_initialized: false,
- service_error: %{code: :domain_not_found}
- }
- })
-
- assert interpretation.data.offer_custom_url_input == true
-
- expected_link_href =
- PlausibleWeb.Router.Helpers.site_path(PlausibleWeb.Endpoint, :verification, "example.com")
-
- html =
- render_component(@component,
- domain: "example.com",
- finished?: true,
- success?: false,
- interpretation: interpretation
- )
-
- assert text_of_element(html, "#verify-custom-url-link") =~ "different URL?"
- assert text_of_attr(html, "#verify-custom-url-link a", "href") =~ expected_link_href
- assert text_of_attr(html, "#verify-custom-url-link a", "href") =~ "custom_url=true"
- end
-
- test "offers escape paths: settings and installation instructions on failure" do
- html =
- render_component(@component,
- domain: "example.com",
- success?: false,
- finished?: true,
- installation_type: "wordpress",
- flow: PlausibleWeb.Flows.review()
- )
-
- assert element_exists?(html, ~s|a[href="/example.com/settings/general"]|)
-
- assert element_exists?(
- html,
- ~s|a[href="/example.com/installation?flow=review&installation_type=wordpress"]|
- )
- end
- end
-end
diff --git a/test/plausible_web/live/installation_test.exs b/test/plausible_web/live/installation_test.exs
index a3ac3aae5f06..7c7adf0fe169 100644
--- a/test/plausible_web/live/installation_test.exs
+++ b/test/plausible_web/live/installation_test.exs
@@ -246,10 +246,11 @@ defmodule PlausibleWeb.Live.InstallationTest do
{"gtm", "Verify Tag Manager installation"},
{"npm", "Verify NPM installation"}
] do
- test "submitting form with #{type} redirects to verification (EE)", %{
- conn: conn,
- site: site
- } do
+ test "submitting form with #{type} redirects to the dashboard with the verification banner (EE)",
+ %{
+ conn: conn,
+ site: site
+ } do
stub_lookup_a_records(site.domain)
stub_detection_manual()
{lv, _html} = get_lv(conn, site, "?type=#{unquote(type)}")
@@ -270,9 +271,9 @@ defmodule PlausibleWeb.Live.InstallationTest do
assert_redirect(
lv,
- Routes.site_path(conn, :verification, site.domain,
- flow: "provisioning",
- installation_type: unquote(type)
+ Routes.stats_path(conn, :stats, site.domain,
+ verify_installation: true,
+ flow: "provisioning"
)
)
end
@@ -280,7 +281,10 @@ defmodule PlausibleWeb.Live.InstallationTest do
end
@tag :ce_build_only
- test "submitting the form redirects to verification (CE)", %{conn: conn, site: site} do
+ test "submitting the form redirects straight to the dashboard, no banner (CE)", %{
+ conn: conn,
+ site: site
+ } do
{lv, _html} = get_lv(conn, site)
lv
@@ -294,13 +298,7 @@ defmodule PlausibleWeb.Live.InstallationTest do
}
})
- assert_redirect(
- lv,
- Routes.site_path(conn, :verification, site.domain,
- flow: "provisioning",
- installation_type: "manual"
- )
- )
+ assert_redirect(lv, Routes.stats_path(conn, :stats, site.domain))
end
test "404 goal gets created regardless of user options", %{conn: conn, site: site} do
@@ -331,10 +329,11 @@ defmodule PlausibleWeb.Live.InstallationTest do
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
+ test "submitting form with review flow redirects to the dashboard with the flow param preserved",
+ %{
+ conn: conn,
+ site: site
+ } do
on_ee do
stub_lookup_a_records(site.domain)
stub_detection_manual()
@@ -356,13 +355,19 @@ defmodule PlausibleWeb.Live.InstallationTest do
}
})
- assert_redirect(
- lv,
- Routes.site_path(conn, :verification, site.domain,
- flow: "review",
- installation_type: "manual"
+ on_ee do
+ assert_redirect(
+ lv,
+ Routes.stats_path(conn, :stats, site.domain,
+ verify_installation: true,
+ flow: "review"
+ )
)
- )
+ end
+
+ on_ce do
+ assert_redirect(lv, Routes.stats_path(conn, :stats, site.domain))
+ end
end
@tag :ee_only
diff --git a/test/plausible_web/live/verification_test.exs b/test/plausible_web/live/verification_test.exs
index 4580e932e96b..4ba6ea3f823c 100644
--- a/test/plausible_web/live/verification_test.exs
+++ b/test/plausible_web/live/verification_test.exs
@@ -9,33 +9,36 @@ defmodule PlausibleWeb.Live.VerificationTest do
setup [:create_user, :log_in, :create_site]
- # @verify_button ~s|button#launch-verification-button[phx-click="launch-verification"]|
@retry_button ~s|a[phx-click="retry"]|
- # @go_to_dashboard_button ~s|a[href$="?skip_to_dashboard=true"]|
@progress ~s|#verification-ui p#progress|
- @awaiting ~s|#verification-ui span#awaiting|
- @heading ~s|#verification-ui h2|
+ @heading ~s|#verification-ui h3|
+ @banner ~s|#verification-ui|
+
+ @in_progress_text "Verifying your installation"
describe "GET /:domain" do
@tag :ee_only
- test "static verification screen renders", %{conn: conn, site: site} do
+ test "static verification banner renders on a freshly provisioned site", %{
+ conn: conn,
+ site: site
+ } do
resp =
- get(conn, conn |> no_slowdown() |> get("/#{site.domain}") |> redirected_to)
+ conn
+ |> no_slowdown()
+ |> get("/#{site.domain}?verify_installation=true")
|> html_response(200)
assert text_of_element(resp, @progress) =~
"We're visiting your site to ensure that everything is working"
- assert resp =~ "Verifying your installation"
+ assert resp =~ @in_progress_text
end
@tag :ce_build_only
- test "static verification screen renders (ce)", %{conn: conn, site: site} do
- resp =
- get(conn, conn |> no_slowdown() |> get("/#{site.domain}") |> redirected_to)
- |> html_response(200)
+ test "no verification banner renders on CE", %{conn: conn, site: site} do
+ resp = get(conn, "/#{site.domain}") |> html_response(200)
- assert resp =~ "Awaiting your first pageview …"
+ refute resp =~ "verification-ui"
end
end
@@ -51,45 +54,61 @@ defmodule PlausibleWeb.Live.VerificationTest do
{_, html} = get_lv(conn, site)
- assert html =~ "Verifying your installation"
+ assert html =~ @in_progress_text
assert text_of_element(html, @progress) =~
"We're visiting your site to ensure that everything is working"
end
- @tag :ce_build_only
- test "LiveView mounts (ce)", %{conn: conn, site: site} do
- {_, html} = get_lv(conn, site)
- assert html =~ "Awaiting your first pageview …"
- end
-
@tag :ee_only
- test "from custom URL input form to verification", %{conn: conn, site: site} do
+ test "clicking the custom URL link reveals an inline form next to the retry button, submitting kicks off a new run",
+ %{
+ conn: conn,
+ site: site
+ } do
stub_lookup_a_records(site.domain)
stub_verification_result(%{
- "completed" => false,
- "error" => %{"message" => "Error"}
+ "completed" => true,
+ "trackerIsInHtml" => false,
+ "plausibleIsOnWindow" => false,
+ "plausibleIsInitialized" => false
})
- # Get liveview with ?custom_url=true query param
- {:ok, lv, html} =
- conn |> no_slowdown() |> live("/#{site.domain}/verification?custom_url=true")
+ {:ok, lv} = kick_off_live_verification(conn, site)
+
+ assert eventually(fn ->
+ html = render(lv)
+
+ {
+ text_of_element(html, @heading) =~ "We couldn't detect Plausible on your site",
+ html
+ }
+ end)
+
+ html = lv |> render_click("show-custom-url-form")
+
+ refute html =~ @in_progress_text
+
+ refute element_exists?(html, @retry_button)
+ refute element_exists?(html, "#verify-custom-url-link")
- verifying_installation_text = "Verifying your installation"
+ assert element_exists?(
+ html,
+ ~s|form[phx-submit="verify-custom-url"] input[name="custom_url"]|
+ )
- # Assert form is rendered instead of kicking off verification automatically
- assert html =~ "Enter Your Custom URL"
assert html =~ ~s[value="https://#{site.domain}"]
assert html =~ ~s[placeholder="https://#{site.domain}"]
- refute html =~ verifying_installation_text
- # Submit custom URL form
- html = lv |> element("form") |> render_submit(%{"custom_url" => "https://abc.de"})
+ lv
+ |> element("form[phx-submit='verify-custom-url']")
+ |> render_submit(%{"custom_url" => "https://abc.de"})
- # Should now show verification progress and hide custom URL form
- assert html =~ verifying_installation_text
- refute html =~ "Enter Your Custom URL"
+ assert eventually(fn ->
+ html = render(lv)
+ {html =~ @in_progress_text, html}
+ end)
end
@tag :ee_only
@@ -113,25 +132,13 @@ defmodule PlausibleWeb.Live.VerificationTest do
assert eventually(fn ->
html = render(lv)
-
- {
- text_of_element(html, @awaiting) =~
- "Awaiting your first pageview",
- html
- }
+ {html =~ "Tracking is active on your site", html}
end)
-
- html = render(lv)
- assert html =~ "Success!"
- assert html =~ "Awaiting your first pageview"
end
@tag :ee_only
- test "won't await first pageview if site has pageviews", %{conn: conn, site: site} do
- populate_stats(site, [
- build(:pageview)
- ])
-
+ test "the dismissed flag keeps the banner hidden even if a late update arrives while still connected",
+ %{conn: conn, site: site} do
stub_lookup_a_records(site.domain)
stub_verification_result(%{
@@ -149,95 +156,63 @@ defmodule PlausibleWeb.Live.VerificationTest do
{:ok, lv} = kick_off_live_verification(conn, site)
+ html = render(lv)
+ assert html =~ @in_progress_text
+ refute class_of_element(html, @banner) =~ "hidden"
+
+ html = render_click(lv, "dismiss")
+ assert class_of_element(html, @banner) =~ "hidden"
+
+ # This might look a bit counter-intuitive -- dismissing the banner
+ # closes the websocket connection and the LV process would normally
+ # die before the component gets notified of success.
+
+ # However, `Phoenix.LiveViewTest` can't simulate a real socket closing,
+ # so the process here just stays alive regardless. What this guards is
+ # the defensive `dismissed?` gate itself: if this process is ever still
+ # around when a late update arrives, for whatever reason, the banner
+ # must stay hidden.
assert eventually(fn ->
html = render(lv)
-
- {
- text(html) =~ "Success",
- html
- }
+ {html =~ "Tracking is active on your site", html}
end)
html = render(lv)
-
- refute text_of_element(html, @awaiting) =~ "Awaiting your first pageview"
- refute_redirected(lv, "/#{URI.encode_www_form(site.domain)}/")
+ assert class_of_element(html, @banner) =~ "hidden"
end
- test "will redirect when first pageview arrives", %{conn: conn, site: site} do
+ @tag :ee_only
+ test "dismissing tells the client to close the websocket connection",
+ %{conn: conn, site: site} do
stub_lookup_a_records(site.domain)
stub_verification_result(%{
- "completed" => true,
- "trackerIsInHtml" => true,
- "plausibleIsOnWindow" => true,
- "plausibleIsInitialized" => true,
- "testEvent" => %{
- "normalizedBody" => %{
- "domain" => site.domain
- },
- "responseStatus" => 200
- }
+ "completed" => false,
+ "error" => %{"message" => "Error"}
})
{:ok, lv} = kick_off_live_verification(conn, site)
- assert eventually(fn ->
- html = render(lv)
-
- {
- text(html) =~ "Awaiting",
- html
- }
- end)
-
- populate_stats(site, [
- build(:pageview)
- ])
-
- assert_redirect(lv, Routes.stats_path(PlausibleWeb.Endpoint, :stats, site.domain))
- end
-
- @tag :ce_build_only
- test "will redirect when first pageview arrives (ce)", %{conn: conn, site: site} do
- {:ok, lv} = kick_off_live_verification(conn, site)
-
- html = render(lv)
- assert text(html) =~ "Awaiting your first pageview …"
-
- populate_stats(site, [build(:pageview)])
+ render_click(lv, "dismiss")
- assert_redirect(lv, Routes.stats_path(PlausibleWeb.Endpoint, :stats, site.domain))
+ assert_push_event(lv, "disconnect-liveview", %{})
end
- for {installation_type_param, expected_text, saved_installation_type} <- [
- {"manual",
- "Please make sure you've copied the snippet to the head of your site, or verify your installation manually.",
- nil},
- {"npm",
- "Please make sure you've initialized Plausible on your site, or verify your installation manually.",
- nil},
- {"gtm",
- "Please make sure you've configured the GTM template correctly, or verify your installation manually.",
- nil},
- {"wordpress",
- "Please make sure you've enabled the plugin, or verify your installation manually.",
- nil},
- # trusts param over saved installation type
- {"wordpress",
- "Please make sure you've enabled the plugin, or verify your installation manually.",
+ for {expected_text, saved_installation_type} <- [
+ {"Make sure you've copied the snippet to the head of your site, or verify your installation manually.",
+ "manual"},
+ {"Make sure you've initialized Plausible on your site, or verify your installation manually.",
"npm"},
- # falls back to saved installation type if no param
- {"",
- "Please make sure you've initialized Plausible on your site, or verify your installation manually.",
- "npm"},
- # falls back to manual if no param and no saved installation type
- {"",
- "Please make sure you've copied the snippet to the head of your site, or verify your installation manually.",
+ {"Make sure you've configured the GTM template correctly, or verify your installation manually.",
+ "gtm"},
+ {"Make sure you've enabled the WordPress plugin, or verify your installation manually.",
+ "wordpress"},
+ # falls back to manual when there's no saved installation type
+ {"Make sure you've copied the snippet to the head of your site, or verify your installation manually.",
nil}
] do
@tag :ee_only
- test "eventually fails to verify installation (?installation_type=#{installation_type_param}) if saved installation type is #{inspect(saved_installation_type)}",
+ test "eventually fails to verify installation if saved installation type is #{inspect(saved_installation_type)}",
%{
conn: conn,
site: site
@@ -257,45 +232,49 @@ defmodule PlausibleWeb.Live.VerificationTest do
})
end
- {:ok, lv} =
- kick_off_live_verification(
- conn,
- site,
- "?installation_type=#{unquote(installation_type_param)}"
- )
-
- assert html =
- eventually(fn ->
- html = render(lv)
- {html =~ "", html}
-
- {
- text_of_element(html, @heading) =~
- "We couldn't detect Plausible on your site",
- html
- }
- end)
+ {:ok, lv} = kick_off_live_verification(conn, site)
+
+ html =
+ eventually(fn ->
+ html = render(lv)
+
+ {
+ text_of_element(html, @heading) =~ "We couldn't detect Plausible on your site",
+ html
+ }
+ end)
assert element_exists?(html, @retry_button)
- assert html =~ htmlize_quotes(unquote(expected_text))
+ assert text_of_element(html, "#recommendation") =~ unquote(expected_text)
refute element_exists?(html, "#super-admin-report")
end
end
end
- defp get_lv(conn, site, qs \\ nil) do
- {:ok, lv, html} = conn |> no_slowdown() |> live("/#{site.domain}/verification#{qs}")
+ defp get_lv(conn, site) do
+ {:ok, lv, html} =
+ conn |> no_slowdown() |> as_live() |> live(verification_path(site))
+
{lv, html}
end
- defp kick_off_live_verification(conn, site, qs \\ nil) do
+ defp kick_off_live_verification(conn, site) do
{:ok, lv, _html} =
- conn |> no_slowdown() |> no_delay() |> live("/#{site.domain}/verification#{qs}")
+ conn |> no_slowdown() |> no_delay() |> as_live() |> live(verification_path(site))
{:ok, lv}
end
+ # `PlausibleWeb.Live.Verification` is rendered via `live_render/3` from a
+ # plain controller-rendered page rather than a live router route, so it
+ # never carries the `:live_module` assign `Phoenix.LiveViewTest.live/2`
+ # looks for. Mirrors the same workaround used in other live_render-embedded
+ # LiveView tests (e.g. props_settings_test.exs).
+ defp as_live(conn), do: assign(conn, :live_module, PlausibleWeb.Live.Verification)
+
+ defp verification_path(site), do: "/#{site.domain}?verify_installation=true"
+
defp no_slowdown(conn) do
Plug.Conn.put_private(conn, :slowdown, 0)
end