Refactor Verification module structure (#5570)
* detector.js * refactor: organize modules better * Renaming (Elixir + JS) * lib/plausible/verification -> lib/plausible/installation_support * test/plausible/verification -> test/plausible/installation_support * priv/tracker/verifier -> priv/tracker/installation_support * tracker/verifier -> tracker/installation_support * tracker/test/verifier -> tracker/test/installation-support * rename remaining test modules * add documentation * dialyzer: remove module refs that do not exist yet * Fix CI * fix tracker CI * fix tracker CI for good
This commit is contained in:
parent
39c006bfb9
commit
97dcc3fe7c
|
|
@ -92,7 +92,7 @@ plausible-report.xml
|
||||||
|
|
||||||
# Auto-generated tracker files
|
# Auto-generated tracker files
|
||||||
/priv/tracker/js/plausible*.js*
|
/priv/tracker/js/plausible*.js*
|
||||||
/priv/tracker/verifier/*.js
|
/priv/tracker/installation_support/*.js
|
||||||
|
|
||||||
# Docker volumes
|
# Docker volumes
|
||||||
.clickhouse_db_vol*
|
.clickhouse_db_vol*
|
||||||
|
|
|
||||||
|
|
@ -937,7 +937,7 @@ config :plausible, Plausible.PromEx,
|
||||||
grafana: :disabled,
|
grafana: :disabled,
|
||||||
metrics_server: :disabled
|
metrics_server: :disabled
|
||||||
|
|
||||||
config :plausible, Plausible.Verification.Checks.Installation,
|
config :plausible, Plausible.InstallationSupport,
|
||||||
token: get_var_from_path_or_env(config_dir, "BROWSERLESS_TOKEN", "dummy_token"),
|
token: get_var_from_path_or_env(config_dir, "BROWSERLESS_TOKEN", "dummy_token"),
|
||||||
endpoint: get_var_from_path_or_env(config_dir, "BROWSERLESS_ENDPOINT", "http://0.0.0.0:3000")
|
endpoint: get_var_from_path_or_env(config_dir, "BROWSERLESS_ENDPOINT", "http://0.0.0.0:3000")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,14 @@ config :plausible, Plausible.Ingestion.Counters, enabled: false
|
||||||
|
|
||||||
config :plausible, Oban, testing: :manual
|
config :plausible, Oban, testing: :manual
|
||||||
|
|
||||||
config :plausible, Plausible.Verification.Checks.FetchBody,
|
config :plausible, Plausible.InstallationSupport.Checks.FetchBody,
|
||||||
req_opts: [
|
req_opts: [
|
||||||
plug: {Req.Test, Plausible.Verification.Checks.FetchBody}
|
plug: {Req.Test, Plausible.InstallationSupport.Checks.FetchBody}
|
||||||
]
|
]
|
||||||
|
|
||||||
config :plausible, Plausible.Verification.Checks.Installation,
|
config :plausible, Plausible.InstallationSupport.Checks.Installation,
|
||||||
req_opts: [
|
req_opts: [
|
||||||
plug: {Req.Test, Plausible.Verification.Checks.Installation}
|
plug: {Req.Test, Plausible.InstallationSupport.Checks.Installation}
|
||||||
]
|
]
|
||||||
|
|
||||||
config :plausible, Plausible.HelpScout,
|
config :plausible, Plausible.HelpScout,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ defmodule Plausible.Ingestion.Event do
|
||||||
salts: nil,
|
salts: nil,
|
||||||
changeset: nil
|
changeset: nil
|
||||||
|
|
||||||
@verification_user_agent Plausible.Verification.user_agent()
|
@verification_user_agent Plausible.InstallationSupport.user_agent()
|
||||||
|
|
||||||
@type drop_reason() ::
|
@type drop_reason() ::
|
||||||
:bot
|
:bot
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
defmodule Plausible.InstallationSupport.Check do
|
||||||
|
@moduledoc """
|
||||||
|
Behaviour to be implemented by a specific installation support check.
|
||||||
|
|
||||||
|
`report_progress_as()` doesn't necessarily reflect the actual check
|
||||||
|
description, it serves as a user-facing message grouping mechanism,
|
||||||
|
to prevent frequent message flashing when checks rotate often.
|
||||||
|
|
||||||
|
Each check operates on `%Plausible.InstallationSupport.State{}` and is
|
||||||
|
expected to return it, optionally modified, by all means. `perform_safe/1`
|
||||||
|
is used to guarantee no exceptions are thrown by faulty implementations,
|
||||||
|
not to interrupt LiveView.
|
||||||
|
"""
|
||||||
|
@type state() :: Plausible.InstallationSupport.State.t()
|
||||||
|
@callback report_progress_as() :: String.t()
|
||||||
|
@callback perform(state()) :: state()
|
||||||
|
|
||||||
|
defmacro __using__(_) do
|
||||||
|
quote do
|
||||||
|
import Plausible.InstallationSupport.State
|
||||||
|
alias Plausible.InstallationSupport.State
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
@behaviour Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
|
def perform_safe(state) do
|
||||||
|
perform(state)
|
||||||
|
catch
|
||||||
|
_, e ->
|
||||||
|
Logger.error(
|
||||||
|
"Error running check #{inspect(__MODULE__)} on #{state.url}: #{inspect(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
put_diagnostics(state, service_error: e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
defmodule Plausible.InstallationSupport.CheckRunner do
|
||||||
|
@moduledoc """
|
||||||
|
Takes two arguments:
|
||||||
|
|
||||||
|
1. A `%Plausible.InstallationSupport.State{}` struct - the `diagnostics`
|
||||||
|
field is a struct representing the set of diagnostics shared between
|
||||||
|
all the checks in this flow.
|
||||||
|
|
||||||
|
2. A list of modules implementing `Plausible.InstallationSupport.Check`
|
||||||
|
behaviour.
|
||||||
|
|
||||||
|
Checks are normally run asynchronously, except when synchronous
|
||||||
|
execution is optionally required for tests. Slowdowns can be optionally
|
||||||
|
added, the user doesn't benefit from running the checks too quickly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def run(state, checks, opts) do
|
||||||
|
async? = Keyword.get(opts, :async?, true)
|
||||||
|
slowdown = Keyword.get(opts, :slowdown, 500)
|
||||||
|
|
||||||
|
if async? do
|
||||||
|
Task.start_link(fn -> do_run(state, checks, slowdown) end)
|
||||||
|
else
|
||||||
|
do_run(state, checks, slowdown)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_run(state, checks, slowdown) do
|
||||||
|
state =
|
||||||
|
Enum.reduce(
|
||||||
|
checks,
|
||||||
|
state,
|
||||||
|
fn check, state ->
|
||||||
|
state
|
||||||
|
|> notify_check_start(check, slowdown)
|
||||||
|
|> check.perform_safe()
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
notify_all_checks_done(state, slowdown)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_check_start(state, check, slowdown) do
|
||||||
|
if is_pid(state.report_to) do
|
||||||
|
if is_integer(slowdown) and slowdown > 0, do: :timer.sleep(slowdown)
|
||||||
|
send(state.report_to, {:check_start, {check, state}})
|
||||||
|
end
|
||||||
|
|
||||||
|
state
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_all_checks_done(state, slowdown) do
|
||||||
|
if is_pid(state.report_to) do
|
||||||
|
if is_integer(slowdown) and slowdown > 0, do: :timer.sleep(slowdown)
|
||||||
|
send(state.report_to, {:all_checks_done, state})
|
||||||
|
end
|
||||||
|
|
||||||
|
state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
defmodule Plausible.Verification.Checks.CSP do
|
defmodule Plausible.InstallationSupport.Checks.CSP do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Scans the Content Security Policy header to ensure that the Plausible domain is allowed.
|
Scans the Content Security Policy header to ensure that the Plausible domain is allowed.
|
||||||
See `Plausible.Verification.Checks` for the execution sequence.
|
See `Plausible.InstallationSupport.LegacyVerification.Checks` for the execution sequence.
|
||||||
"""
|
"""
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "We're visiting your site to ensure that everything is working"
|
def report_progress_as, do: "We're visiting your site to ensure that everything is working"
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
defmodule Plausible.Verification.Checks.FetchBody do
|
defmodule Plausible.InstallationSupport.Checks.FetchBody do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Fetches the body of the site and extracts the HTML document, if available, for
|
Fetches the body of the site and extracts the HTML document, if available, for
|
||||||
further processing.
|
further processing. See `Plausible.InstallationSupport.LegacyVerification.Checks`
|
||||||
See `Plausible.Verification.Checks` for the execution sequence.
|
for the execution sequence.
|
||||||
"""
|
"""
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "We're visiting your site to ensure that everything is working"
|
def report_progress_as, do: "We're visiting your site to ensure that everything is working"
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
||||||
def perform(%State{url: "https://" <> _ = url} = state) do
|
def perform(%State{url: "https://" <> _ = url} = state) do
|
||||||
fetch_body_opts = Application.get_env(:plausible, __MODULE__)[:req_opts] || []
|
fetch_body_opts = Application.get_env(:plausible, __MODULE__)[:req_opts] || []
|
||||||
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
defmodule Plausible.Verification.Checks.Installation do
|
defmodule Plausible.InstallationSupport.Checks.Installation do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
path = Application.app_dir(:plausible, "priv/tracker/verifier/verifier-v1.js")
|
path = Application.app_dir(:plausible, "priv/tracker/installation_support/verifier-v1.js")
|
||||||
# On CI, the file might not be present for static checks so we create an empty one
|
# On CI, the file might not be present for static checks so we create an empty one
|
||||||
File.touch!(path)
|
File.touch!(path)
|
||||||
|
|
||||||
@verifier_code File.read!(path)
|
@verifier_code File.read!(path)
|
||||||
@external_resource "priv/tracker/verifier/verifier-v1.js"
|
@external_resource "priv/tracker/installation_support/verifier-v1.js"
|
||||||
|
|
||||||
# Puppeteer wrapper function that executes the vanilla JS verifier code
|
# Puppeteer wrapper function that executes the vanilla JS verifier code
|
||||||
@puppeteer_wrapper_code """
|
@puppeteer_wrapper_code """
|
||||||
|
|
@ -45,7 +45,7 @@ defmodule Plausible.Verification.Checks.Installation do
|
||||||
|
|
||||||
- `data.callbackStatus` - integer. 202 indicates that the server acknowledged the test event.
|
- `data.callbackStatus` - integer. 202 indicates that the server acknowledged the test event.
|
||||||
The test event ingestion is discarded based on user-agent, see:
|
The test event ingestion is discarded based on user-agent, see:
|
||||||
`Plausible.Verification.user_agent/0`
|
`Plausible.InstallationSupport.user_agent/0`
|
||||||
|
|
||||||
- `data.dataDomainMismatch` - whether or not script[data-domain] mismatched with site.domain
|
- `data.dataDomainMismatch` - whether or not script[data-domain] mismatched with site.domain
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ defmodule Plausible.Verification.Checks.Installation do
|
||||||
|
|
||||||
- `data.cookieBannerLikely` - whether or not there's a cookie banner blocking Plausible
|
- `data.cookieBannerLikely` - whether or not there's a cookie banner blocking Plausible
|
||||||
"""
|
"""
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "We're verifying that your visitors are being counted correctly"
|
def report_progress_as, do: "We're verifying that your visitors are being counted correctly"
|
||||||
|
|
@ -77,8 +77,8 @@ defmodule Plausible.Verification.Checks.Installation do
|
||||||
code: @puppeteer_wrapper_code,
|
code: @puppeteer_wrapper_code,
|
||||||
context: %{
|
context: %{
|
||||||
expectedDataDomain: data_domain,
|
expectedDataDomain: data_domain,
|
||||||
url: Plausible.Verification.URL.bust_url(url),
|
url: Plausible.InstallationSupport.URL.bust_url(url),
|
||||||
userAgent: Plausible.Verification.user_agent(),
|
userAgent: Plausible.InstallationSupport.user_agent(),
|
||||||
debug: Application.get_env(:plausible, :environment) == "dev"
|
debug: Application.get_env(:plausible, :environment) == "dev"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
@ -90,7 +90,7 @@ defmodule Plausible.Verification.Checks.Installation do
|
||||||
extra_opts = Application.get_env(:plausible, __MODULE__)[:req_opts] || []
|
extra_opts = Application.get_env(:plausible, __MODULE__)[:req_opts] || []
|
||||||
opts = Keyword.merge(opts, extra_opts)
|
opts = Keyword.merge(opts, extra_opts)
|
||||||
|
|
||||||
case Req.post(verification_endpoint(), opts) do
|
case Req.post(Plausible.InstallationSupport.browserless_function_api_endpoint(), opts) do
|
||||||
{:ok, %{status: 200, body: %{"data" => %{"completed" => true} = js_data}}} ->
|
{:ok, %{status: 200, body: %{"data" => %{"completed" => true} = js_data}}} ->
|
||||||
emit_telemetry_and_log(state.diagnostics, js_data, data_domain)
|
emit_telemetry_and_log(state.diagnostics, js_data, data_domain)
|
||||||
|
|
||||||
|
|
@ -159,11 +159,4 @@ defmodule Plausible.Verification.Checks.Installation do
|
||||||
|
|
||||||
:telemetry.execute(telemetry_event(any_diff?), %{})
|
:telemetry.execute(telemetry_event(any_diff?), %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp verification_endpoint() do
|
|
||||||
config = Application.fetch_env!(:plausible, __MODULE__)
|
|
||||||
token = Keyword.fetch!(config, :token)
|
|
||||||
endpoint = Keyword.fetch!(config, :endpoint)
|
|
||||||
Path.join(endpoint, "function?token=#{token}&stealth")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
defmodule Plausible.Verification.Checks.ScanBody do
|
defmodule Plausible.InstallationSupport.Checks.ScanBody do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Naive way of detecting GTM and WordPress powered sites.
|
Naive way of detecting GTM and WordPress powered sites.
|
||||||
"""
|
"""
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "We're visiting your site to ensure that everything is working"
|
def report_progress_as, do: "We're visiting your site to ensure that everything is working"
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
defmodule Plausible.Verification.Checks.Snippet do
|
defmodule Plausible.InstallationSupport.Checks.Snippet do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
The check looks for Plausible snippets and tries to address the common
|
The check looks for Plausible snippets and tries to address the common
|
||||||
integration issues, such as bad placement, data-domain typos, unknown
|
integration issues, such as bad placement, data-domain typos, unknown
|
||||||
attributes frequently added by performance optimization plugins, etc.
|
attributes frequently added by performance optimization plugins, etc.
|
||||||
"""
|
"""
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "We're looking for the Plausible snippet on your site"
|
def report_progress_as, do: "We're looking for the Plausible snippet on your site"
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
defmodule Plausible.Verification.Checks.SnippetCacheBust do
|
defmodule Plausible.InstallationSupport.Checks.SnippetCacheBust do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
A naive way of trying to figure out whether the latest site contents
|
A naive way of trying to figure out whether the latest site contents
|
||||||
is wrapped with some CDN/caching layer.
|
is wrapped with some CDN/caching layer.
|
||||||
In case no snippets were found, we'll try to bust the cache by appending a random query parameter
|
|
||||||
and re-run `Plausible.Verification.Checks.FetchBody` and `Plausible.Verification.Checks.Snippet` checks.
|
In case no snippets were found, we'll try to bust the cache by appending
|
||||||
|
a random query parameter and re-run `FetchBody` and `Snippet` checks.
|
||||||
If the result is different this time, we'll assume cache likely.
|
If the result is different this time, we'll assume cache likely.
|
||||||
"""
|
"""
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
|
alias Plausible.InstallationSupport.{LegacyVerification, Checks, URL}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "We're looking for the Plausible snippet on your site"
|
def report_progress_as, do: "We're looking for the Plausible snippet on your site"
|
||||||
|
|
@ -15,7 +18,7 @@ defmodule Plausible.Verification.Checks.SnippetCacheBust do
|
||||||
def perform(
|
def perform(
|
||||||
%State{
|
%State{
|
||||||
url: url,
|
url: url,
|
||||||
diagnostics: %Diagnostics{
|
diagnostics: %LegacyVerification.Diagnostics{
|
||||||
snippets_found_in_head: 0,
|
snippets_found_in_head: 0,
|
||||||
snippets_found_in_body: 0,
|
snippets_found_in_body: 0,
|
||||||
body_fetched?: true
|
body_fetched?: true
|
||||||
|
|
@ -23,10 +26,10 @@ defmodule Plausible.Verification.Checks.SnippetCacheBust do
|
||||||
} = state
|
} = state
|
||||||
) do
|
) do
|
||||||
state2 =
|
state2 =
|
||||||
%{state | url: Plausible.Verification.URL.bust_url(url)}
|
%{state | url: URL.bust_url(url)}
|
||||||
|> Plausible.Verification.Checks.FetchBody.perform()
|
|> Checks.FetchBody.perform()
|
||||||
|> Plausible.Verification.Checks.ScanBody.perform()
|
|> Checks.ScanBody.perform()
|
||||||
|> Plausible.Verification.Checks.Snippet.perform()
|
|> Checks.Snippet.perform()
|
||||||
|
|
||||||
if state2.diagnostics.snippets_found_in_head > 0 or
|
if state2.diagnostics.snippets_found_in_head > 0 or
|
||||||
state2.diagnostics.snippets_found_in_body > 0 do
|
state2.diagnostics.snippets_found_in_body > 0 do
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
defmodule Plausible.InstallationSupport do
|
||||||
|
@moduledoc """
|
||||||
|
This top level module is the middle ground between pre-installation
|
||||||
|
site scans and verification of whether Plausible has been installed
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
Defines the user-agent used by Elixir-native HTTP requests as well
|
||||||
|
as headless browser checks on the client side via Browserless.
|
||||||
|
"""
|
||||||
|
use Plausible
|
||||||
|
|
||||||
|
on_ee do
|
||||||
|
def user_agent() do
|
||||||
|
"Plausible Verification Agent - if abused, contact support@plausible.io"
|
||||||
|
end
|
||||||
|
|
||||||
|
def browserless_function_api_endpoint() do
|
||||||
|
config = Application.fetch_env!(:plausible, __MODULE__)
|
||||||
|
token = Keyword.fetch!(config, :token)
|
||||||
|
endpoint = Keyword.fetch!(config, :endpoint)
|
||||||
|
Path.join(endpoint, "function?token=#{token}&stealth")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
def browserless_function_api_endpoint() do
|
||||||
|
"Browserless API should not be called on Community Edition"
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_agent() do
|
||||||
|
"Plausible Community Edition"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
defmodule Plausible.InstallationSupport.LegacyVerification.Checks do
|
||||||
|
@moduledoc """
|
||||||
|
Checks that are performed during v1 site verification.
|
||||||
|
|
||||||
|
In async execution, each check notifies the caller by sending a message to it.
|
||||||
|
"""
|
||||||
|
alias Plausible.InstallationSupport.LegacyVerification
|
||||||
|
alias Plausible.InstallationSupport.{State, CheckRunner, Checks}
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
@checks [
|
||||||
|
Checks.FetchBody,
|
||||||
|
Checks.CSP,
|
||||||
|
Checks.ScanBody,
|
||||||
|
Checks.Snippet,
|
||||||
|
Checks.SnippetCacheBust,
|
||||||
|
Checks.Installation
|
||||||
|
]
|
||||||
|
|
||||||
|
def run(url, data_domain, opts \\ []) do
|
||||||
|
checks = Keyword.get(opts, :checks, @checks)
|
||||||
|
report_to = Keyword.get(opts, :report_to, self())
|
||||||
|
async? = Keyword.get(opts, :async?, true)
|
||||||
|
slowdown = Keyword.get(opts, :slowdown, 500)
|
||||||
|
|
||||||
|
init_state =
|
||||||
|
%State{
|
||||||
|
url: url,
|
||||||
|
data_domain: data_domain,
|
||||||
|
report_to: report_to,
|
||||||
|
diagnostics: %LegacyVerification.Diagnostics{}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckRunner.run(init_state, checks,
|
||||||
|
async?: async?,
|
||||||
|
report_to: report_to,
|
||||||
|
slowdown: slowdown
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def interpret_diagnostics(%State{} = state) do
|
||||||
|
LegacyVerification.Diagnostics.interpret(
|
||||||
|
state.diagnostics,
|
||||||
|
state.url
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
defmodule Plausible.Verification.Diagnostics do
|
defmodule Plausible.InstallationSupport.LegacyVerification.Diagnostics do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Module responsible for translating diagnostics to user-friendly errors and recommendations.
|
Module responsible for translating diagnostics to user-friendly errors and recommendations.
|
||||||
"""
|
"""
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@errors Plausible.Verification.Errors.all()
|
@errors Plausible.InstallationSupport.LegacyVerification.Errors.all()
|
||||||
|
|
||||||
defstruct plausible_installed?: false,
|
defstruct plausible_installed?: false,
|
||||||
snippets_found_in_head: 0,
|
snippets_found_in_head: 0,
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule Plausible.Verification.Errors do
|
defmodule Plausible.InstallationSupport.LegacyVerification.Errors do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
A go-to definition of all verification errors
|
A go-to definition of all legacy verification errors
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@errors %{
|
@errors %{
|
||||||
|
|
@ -1,17 +1,26 @@
|
||||||
defmodule Plausible.Verification.State do
|
defmodule Plausible.InstallationSupport.State do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
The struct and interface describing the state of the site verification process.
|
The state to be shared across check during site installation support.
|
||||||
Assigns are meant to be used to communicate between checks, while diagnostics
|
|
||||||
are later on interpreted (translated into user-friendly messages and recommendations)
|
Assigns are meant to be used to communicate between checks, while
|
||||||
via `Plausible.Verification.Diagnostics` module.
|
`diagnostics` are specific to the check group being executed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
defstruct url: nil,
|
defstruct url: nil,
|
||||||
data_domain: nil,
|
data_domain: nil,
|
||||||
report_to: nil,
|
report_to: nil,
|
||||||
assigns: %{},
|
assigns: %{},
|
||||||
diagnostics: %Plausible.Verification.Diagnostics{}
|
diagnostics: %{}
|
||||||
|
|
||||||
@type t() :: %__MODULE__{}
|
@type diagnostics_type :: Plausible.InstallationSupport.LegacyVerification.Diagnostics.t()
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{
|
||||||
|
url: String.t() | nil,
|
||||||
|
data_domain: String.t() | nil,
|
||||||
|
report_to: pid() | nil,
|
||||||
|
assigns: map(),
|
||||||
|
diagnostics: diagnostics_type()
|
||||||
|
}
|
||||||
|
|
||||||
def assign(%__MODULE__{} = state, assigns) do
|
def assign(%__MODULE__{} = state, assigns) do
|
||||||
%{state | assigns: Map.merge(state.assigns, Enum.into(assigns, %{}))}
|
%{state | assigns: Map.merge(state.assigns, Enum.into(assigns, %{}))}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule Plausible.Verification.URL do
|
defmodule Plausible.InstallationSupport.URL do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Busting some caches by appending ?plausible_verification=12345 to it.
|
URL utilities for installation support, including cache busting functionality.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def bust_url(url) do
|
def bust_url(url) do
|
||||||
|
|
@ -124,11 +124,13 @@ defmodule Plausible.PromEx.Plugins.PlausibleMetrics do
|
||||||
),
|
),
|
||||||
counter(
|
counter(
|
||||||
metric_prefix ++ [:verification, :js_elixir_diff],
|
metric_prefix ++ [:verification, :js_elixir_diff],
|
||||||
event_name: Plausible.Verification.Checks.Installation.telemetry_event(_diff = true)
|
event_name:
|
||||||
|
Plausible.InstallationSupport.Checks.Installation.telemetry_event(_diff = true)
|
||||||
),
|
),
|
||||||
counter(
|
counter(
|
||||||
metric_prefix ++ [:verification, :js_elixir_match],
|
metric_prefix ++ [:verification, :js_elixir_match],
|
||||||
event_name: Plausible.Verification.Checks.Installation.telemetry_event(_diff = false)
|
event_name:
|
||||||
|
Plausible.InstallationSupport.Checks.Installation.telemetry_event(_diff = false)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
defmodule Plausible.Verification do
|
|
||||||
@moduledoc """
|
|
||||||
Module defining the user-agent used for site verification.
|
|
||||||
"""
|
|
||||||
use Plausible
|
|
||||||
|
|
||||||
on_ee do
|
|
||||||
def user_agent() do
|
|
||||||
"Plausible Verification Agent - if abused, contact support@plausible.io"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
def user_agent() do
|
|
||||||
"Plausible Community Edition"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
defmodule Plausible.Verification.Check do
|
|
||||||
@moduledoc """
|
|
||||||
Behaviour to be implemented by specific site verification checks.
|
|
||||||
`report_progress_as()` doesn't necessarily reflect the actual check description,
|
|
||||||
it serves as a user-facing message grouping mechanism, to prevent frequent message flashing when checks rotate often.
|
|
||||||
Each check operates on `state()` and is expected to return it, optionally modified, by all means.
|
|
||||||
`perform_safe/1` is used to guarantee no exceptions are thrown by faulty implementations, not to interrupt LiveView.
|
|
||||||
"""
|
|
||||||
@type state() :: Plausible.Verification.State.t()
|
|
||||||
@callback report_progress_as() :: String.t()
|
|
||||||
@callback perform(state()) :: state()
|
|
||||||
|
|
||||||
defmacro __using__(_) do
|
|
||||||
quote do
|
|
||||||
import Plausible.Verification.State
|
|
||||||
|
|
||||||
alias Plausible.Verification.Checks
|
|
||||||
alias Plausible.Verification.State
|
|
||||||
alias Plausible.Verification.Diagnostics
|
|
||||||
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
@behaviour Plausible.Verification.Check
|
|
||||||
|
|
||||||
def perform_safe(state) do
|
|
||||||
perform(state)
|
|
||||||
catch
|
|
||||||
_, e ->
|
|
||||||
Logger.error(
|
|
||||||
"Error running check #{inspect(__MODULE__)} on #{state.url}: #{inspect(e)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
put_diagnostics(state, service_error: e)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
defmodule Plausible.Verification.Checks do
|
|
||||||
@moduledoc """
|
|
||||||
Checks that are performed during site verification.
|
|
||||||
Each module defined in `@checks` implements the `Plausible.Verification.Check` behaviour.
|
|
||||||
Checks are normally run asynchronously, except when synchronous execution is optionally required
|
|
||||||
for tests. Slowdowns can be optionally added, the user doesn't benefit from running the checks too quickly.
|
|
||||||
|
|
||||||
In async execution, each check notifies the caller by sending a message to it.
|
|
||||||
"""
|
|
||||||
alias Plausible.Verification.Checks
|
|
||||||
alias Plausible.Verification.State
|
|
||||||
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
@checks [
|
|
||||||
Checks.FetchBody,
|
|
||||||
Checks.CSP,
|
|
||||||
Checks.ScanBody,
|
|
||||||
Checks.Snippet,
|
|
||||||
Checks.SnippetCacheBust,
|
|
||||||
Checks.Installation
|
|
||||||
]
|
|
||||||
|
|
||||||
def run(url, data_domain, opts \\ []) do
|
|
||||||
checks = Keyword.get(opts, :checks, @checks)
|
|
||||||
report_to = Keyword.get(opts, :report_to, self())
|
|
||||||
async? = Keyword.get(opts, :async?, true)
|
|
||||||
slowdown = Keyword.get(opts, :slowdown, 500)
|
|
||||||
|
|
||||||
if async? do
|
|
||||||
Task.start_link(fn -> do_run(url, data_domain, checks, report_to, slowdown) end)
|
|
||||||
else
|
|
||||||
do_run(url, data_domain, checks, report_to, slowdown)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def interpret_diagnostics(%State{} = state) do
|
|
||||||
Plausible.Verification.Diagnostics.interpret(state.diagnostics, state.url)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_run(url, data_domain, checks, report_to, slowdown) do
|
|
||||||
init_state = %State{url: url, data_domain: data_domain, report_to: report_to}
|
|
||||||
|
|
||||||
state =
|
|
||||||
Enum.reduce(
|
|
||||||
checks,
|
|
||||||
init_state,
|
|
||||||
fn check, state ->
|
|
||||||
state
|
|
||||||
|> notify_start(check, slowdown)
|
|
||||||
|> check.perform_safe()
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
notify_verification_end(state, slowdown)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp notify_start(state, check, slowdown) do
|
|
||||||
if is_pid(state.report_to) do
|
|
||||||
if is_integer(slowdown) and slowdown > 0, do: :timer.sleep(slowdown)
|
|
||||||
send(state.report_to, {:verification_check_start, {check, state}})
|
|
||||||
end
|
|
||||||
|
|
||||||
state
|
|
||||||
end
|
|
||||||
|
|
||||||
defp notify_verification_end(state, slowdown) do
|
|
||||||
if is_pid(state.report_to) do
|
|
||||||
if is_integer(slowdown) and slowdown > 0, do: :timer.sleep(slowdown)
|
|
||||||
send(state.report_to, {:verification_end, state})
|
|
||||||
end
|
|
||||||
|
|
||||||
state
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -7,6 +7,7 @@ defmodule PlausibleWeb.Live.Components.Verification do
|
||||||
use Plausible
|
use Plausible
|
||||||
|
|
||||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||||
|
alias Plausible.InstallationSupport.{State, LegacyVerification}
|
||||||
|
|
||||||
import PlausibleWeb.Components.Generic
|
import PlausibleWeb.Components.Generic
|
||||||
|
|
||||||
|
|
@ -19,8 +20,8 @@ defmodule PlausibleWeb.Live.Components.Verification do
|
||||||
attr(:super_admin?, :boolean, default: false)
|
attr(:super_admin?, :boolean, default: false)
|
||||||
attr(:finished?, :boolean, default: false)
|
attr(:finished?, :boolean, default: false)
|
||||||
attr(:success?, :boolean, default: false)
|
attr(:success?, :boolean, default: false)
|
||||||
attr(:verification_state, Plausible.Verification.State, default: nil)
|
attr(:verification_state, State, default: nil)
|
||||||
attr(:interpretation, Plausible.Verification.Diagnostics.Result, default: nil)
|
attr(:interpretation, LegacyVerification.Diagnostics.Result, default: nil)
|
||||||
attr(:attempts, :integer, default: 0)
|
attr(:attempts, :integer, default: 0)
|
||||||
attr(:flow, :string, default: "")
|
attr(:flow, :string, default: "")
|
||||||
attr(:installation_type, :string, default: nil)
|
attr(:installation_type, :string, default: nil)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ defmodule PlausibleWeb.Live.Installation do
|
||||||
User assistance module around Plausible installation instructions/onboarding
|
User assistance module around Plausible installation instructions/onboarding
|
||||||
"""
|
"""
|
||||||
use PlausibleWeb, :live_view
|
use PlausibleWeb, :live_view
|
||||||
alias Plausible.Verification.{Checks, State}
|
alias Plausible.InstallationSupport.{State, Checks, LegacyVerification}
|
||||||
|
|
||||||
@script_extension_params %{
|
@script_extension_params %{
|
||||||
"outbound_links" => "outbound-links",
|
"outbound_links" => "outbound-links",
|
||||||
|
|
@ -60,7 +60,7 @@ defmodule PlausibleWeb.Live.Installation do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if connected?(socket) and is_nil(installation_type) do
|
if connected?(socket) and is_nil(installation_type) do
|
||||||
Checks.run("https://#{domain}", domain,
|
LegacyVerification.Checks.run("https://#{domain}", domain,
|
||||||
checks: [
|
checks: [
|
||||||
Checks.FetchBody,
|
Checks.FetchBody,
|
||||||
Checks.ScanBody
|
Checks.ScanBody
|
||||||
|
|
@ -86,7 +86,7 @@ defmodule PlausibleWeb.Live.Installation do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({:verification_end, %State{} = state}, socket) do
|
def handle_info({:all_checks_done, %State{} = state}, socket) do
|
||||||
installation_type =
|
installation_type =
|
||||||
case state.diagnostics do
|
case state.diagnostics do
|
||||||
%{wordpress_likely?: true} -> "wordpress"
|
%{wordpress_likely?: true} -> "wordpress"
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ defmodule PlausibleWeb.Live.InstallationV2 do
|
||||||
User assistance module around Plausible installation instructions/onboarding
|
User assistance module around Plausible installation instructions/onboarding
|
||||||
"""
|
"""
|
||||||
alias PlausibleWeb.Flows
|
alias PlausibleWeb.Flows
|
||||||
|
alias Plausible.InstallationSupport.{State, Checks, LegacyVerification}
|
||||||
use PlausibleWeb, :live_view
|
use PlausibleWeb, :live_view
|
||||||
alias Plausible.Verification.{Checks, State}
|
|
||||||
|
|
||||||
def mount(
|
def mount(
|
||||||
%{"domain" => domain} = params,
|
%{"domain" => domain} = params,
|
||||||
|
|
@ -34,7 +34,7 @@ defmodule PlausibleWeb.Live.InstallationV2 do
|
||||||
connected?(socket) and flow == Flows.provisioning() and !params["type"]
|
connected?(socket) and flow == Flows.provisioning() and !params["type"]
|
||||||
|
|
||||||
if detect_installation_type? do
|
if detect_installation_type? do
|
||||||
Checks.run("https://#{site.domain}", site.domain,
|
LegacyVerification.Checks.run("https://#{site.domain}", site.domain,
|
||||||
checks: [
|
checks: [
|
||||||
Checks.FetchBody,
|
Checks.FetchBody,
|
||||||
Checks.ScanBody
|
Checks.ScanBody
|
||||||
|
|
@ -62,7 +62,7 @@ defmodule PlausibleWeb.Live.InstallationV2 do
|
||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({:verification_end, %State{} = state}, socket) do
|
def handle_info({:all_checks_done, %State{} = state}, socket) do
|
||||||
installation_type =
|
installation_type =
|
||||||
case state.diagnostics do
|
case state.diagnostics do
|
||||||
%{wordpress_likely?: true} -> "wordpress"
|
%{wordpress_likely?: true} -> "wordpress"
|
||||||
|
|
@ -77,7 +77,7 @@ defmodule PlausibleWeb.Live.InstallationV2 do
|
||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({:verification_check_start, _}, socket) do
|
def handle_info({:check_start, _}, socket) do
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ defmodule PlausibleWeb.Live.Verification do
|
||||||
use Plausible
|
use Plausible
|
||||||
use PlausibleWeb, :live_view
|
use PlausibleWeb, :live_view
|
||||||
|
|
||||||
alias Plausible.Verification.{Checks, State}
|
alias Plausible.InstallationSupport.{State, LegacyVerification}
|
||||||
|
|
||||||
@component PlausibleWeb.Live.Components.Verification
|
@component PlausibleWeb.Live.Components.Verification
|
||||||
@slowdown_for_frequent_checking :timer.seconds(5)
|
@slowdown_for_frequent_checking :timer.seconds(5)
|
||||||
|
|
@ -132,7 +132,7 @@ defmodule PlausibleWeb.Live.Verification do
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, pid} =
|
{:ok, pid} =
|
||||||
Checks.run(
|
LegacyVerification.Checks.run(
|
||||||
"https://#{socket.assigns.domain}",
|
"https://#{socket.assigns.domain}",
|
||||||
socket.assigns.domain,
|
socket.assigns.domain,
|
||||||
report_to: report_to,
|
report_to: report_to,
|
||||||
|
|
@ -143,7 +143,7 @@ defmodule PlausibleWeb.Live.Verification do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({:verification_check_start, {check, _state}}, socket) do
|
def handle_info({:check_start, {check, _state}}, socket) do
|
||||||
update_component(socket,
|
update_component(socket,
|
||||||
message: check.report_progress_as()
|
message: check.report_progress_as()
|
||||||
)
|
)
|
||||||
|
|
@ -151,8 +151,8 @@ defmodule PlausibleWeb.Live.Verification do
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({:verification_end, %State{} = state}, socket) do
|
def handle_info({:all_checks_done, %State{} = state}, socket) do
|
||||||
interpretation = Checks.interpret_diagnostics(state)
|
interpretation = LegacyVerification.Checks.interpret_diagnostics(state)
|
||||||
|
|
||||||
if not socket.assigns.has_pageviews? do
|
if not socket.assigns.has_pageviews? do
|
||||||
schedule_pageviews_check(socket)
|
schedule_pageviews_check(socket)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||||
assert_receive :telemetry_handled
|
assert_receive :telemetry_handled
|
||||||
end
|
end
|
||||||
|
|
||||||
test "drops verification agent" do
|
test "drops installation support user agent" do
|
||||||
site = new_site()
|
site = new_site()
|
||||||
|
|
||||||
payload = %{
|
payload = %{
|
||||||
|
|
@ -90,7 +90,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
build_conn(:post, "/api/events", payload)
|
build_conn(:post, "/api/events", payload)
|
||||||
|> Plug.Conn.put_req_header("user-agent", Plausible.Verification.user_agent())
|
|> Plug.Conn.put_req_header("user-agent", Plausible.InstallationSupport.user_agent())
|
||||||
|
|
||||||
assert {:ok, request} = Request.build(conn)
|
assert {:ok, request} = Request.build(conn)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
defmodule Plausible.Verification.Checks.CSPTest do
|
defmodule Plausible.InstallationSupport.Checks.CSPTest do
|
||||||
use Plausible.DataCase, async: true
|
use Plausible.DataCase, async: true
|
||||||
|
|
||||||
alias Plausible.Verification.State
|
alias Plausible.InstallationSupport.{State, LegacyVerification}
|
||||||
|
|
||||||
@check Plausible.Verification.Checks.CSP
|
@check Plausible.InstallationSupport.Checks.CSP
|
||||||
|
@default_state %State{diagnostics: %LegacyVerification.Diagnostics{}}
|
||||||
|
|
||||||
test "skips no headers" do
|
test "skips no headers" do
|
||||||
state = %State{}
|
state = @default_state
|
||||||
assert ^state = @check.perform(state)
|
assert ^state = @check.perform(state)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "skips no headers 2" do
|
test "skips no headers 2" do
|
||||||
state = %State{} |> State.assign(headers: %{})
|
state = @default_state |> State.assign(headers: %{})
|
||||||
assert ^state = @check.perform(state)
|
assert ^state = @check.perform(state)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ defmodule Plausible.Verification.Checks.CSPTest do
|
||||||
headers = %{"content-security-policy" => ["default-src 'self' foo.local; example.com"]}
|
headers = %{"content-security-policy" => ["default-src 'self' foo.local; example.com"]}
|
||||||
|
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(headers: headers)
|
|> State.assign(headers: headers)
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -30,7 +31,7 @@ defmodule Plausible.Verification.Checks.CSPTest do
|
||||||
headers = %{"content-security-policy" => ["default-src 'self' example.com; localhost"]}
|
headers = %{"content-security-policy" => ["default-src 'self' example.com; localhost"]}
|
||||||
|
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(headers: headers)
|
|> State.assign(headers: headers)
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
defmodule Plausible.Verification.Checks.FetchBodyTest do
|
defmodule Plausible.InstallationSupport.Checks.FetchBodyTest do
|
||||||
use Plausible.DataCase, async: true
|
use Plausible.DataCase, async: true
|
||||||
|
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
@check Plausible.Verification.Checks.FetchBody
|
alias Plausible.InstallationSupport.{State, Checks, LegacyVerification}
|
||||||
|
|
||||||
|
@check Checks.FetchBody
|
||||||
|
|
||||||
@normal_body """
|
@normal_body """
|
||||||
<html>
|
<html>
|
||||||
|
|
@ -16,8 +18,9 @@ defmodule Plausible.Verification.Checks.FetchBodyTest do
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
{:ok,
|
{:ok,
|
||||||
state: %Plausible.Verification.State{
|
state: %State{
|
||||||
url: "https://example.com"
|
url: "https://example.com",
|
||||||
|
diagnostics: %LegacyVerification.Diagnostics{}
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
defmodule Plausible.Verification.Checks.ScanBodyTest do
|
defmodule Plausible.InstallationSupport.Checks.ScanBodyTest do
|
||||||
use Plausible.DataCase, async: true
|
use Plausible.DataCase, async: true
|
||||||
|
|
||||||
alias Plausible.Verification.State
|
alias Plausible.InstallationSupport.{State, Checks, LegacyVerification}
|
||||||
|
|
||||||
@check Plausible.Verification.Checks.ScanBody
|
@check Checks.ScanBody
|
||||||
|
@default_state %State{diagnostics: %LegacyVerification.Diagnostics{}}
|
||||||
|
|
||||||
test "skips on no raw body" do
|
test "skips on no raw body" do
|
||||||
state = %State{}
|
assert @default_state = @check.perform(@default_state)
|
||||||
assert ^state = @check.perform(state)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "detects nothing" do
|
test "detects nothing" do
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(raw_body: "...")
|
|> State.assign(raw_body: "...")
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ defmodule Plausible.Verification.Checks.ScanBodyTest do
|
||||||
|
|
||||||
test "detects GTM" do
|
test "detects GTM" do
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(raw_body: "...googletagmanager.com/gtm.js...")
|
|> State.assign(raw_body: "...googletagmanager.com/gtm.js...")
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ defmodule Plausible.Verification.Checks.ScanBodyTest do
|
||||||
|
|
||||||
test "detects GTM and cookie banner" do
|
test "detects GTM and cookie banner" do
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(raw_body: "...googletagmanager.com/gtm.js...cookiebot...")
|
|> State.assign(raw_body: "...googletagmanager.com/gtm.js...cookiebot...")
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ defmodule Plausible.Verification.Checks.ScanBodyTest do
|
||||||
for signature <- ["wp-content", "wp-includes", "wp-json"] do
|
for signature <- ["wp-content", "wp-includes", "wp-json"] do
|
||||||
test "detects WordPress: #{signature}" do
|
test "detects WordPress: #{signature}" do
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(raw_body: "...#{unquote(signature)}...")
|
|> State.assign(raw_body: "...#{unquote(signature)}...")
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ defmodule Plausible.Verification.Checks.ScanBodyTest do
|
||||||
|
|
||||||
test "detects GTM and WordPress" do
|
test "detects GTM and WordPress" do
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(raw_body: "...googletagmanager.com/gtm.js....wp-content...")
|
|> State.assign(raw_body: "...googletagmanager.com/gtm.js....wp-content...")
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ defmodule Plausible.Verification.Checks.ScanBodyTest do
|
||||||
|
|
||||||
test "detects official plugin" do
|
test "detects official plugin" do
|
||||||
state =
|
state =
|
||||||
%State{}
|
@default_state
|
||||||
|> State.assign(raw_body: @d, document: Floki.parse_document!(@d))
|
|> State.assign(raw_body: @d, document: Floki.parse_document!(@d))
|
||||||
|> @check.perform()
|
|> @check.perform()
|
||||||
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
defmodule Plausible.Verification.Checks.SnippetTest do
|
defmodule Plausible.InstallationSupport.Checks.SnippetTest do
|
||||||
use Plausible.DataCase, async: true
|
use Plausible.DataCase, async: true
|
||||||
|
|
||||||
alias Plausible.Verification.State
|
alias Plausible.InstallationSupport.{State, Checks, LegacyVerification}
|
||||||
|
|
||||||
@check Plausible.Verification.Checks.Snippet
|
@check Checks.Snippet
|
||||||
|
@default_state %State{diagnostics: %LegacyVerification.Diagnostics{}}
|
||||||
|
|
||||||
test "skips when there's no document" do
|
test "skips when there's no document" do
|
||||||
state = %State{}
|
state = @default_state
|
||||||
assert ^state = @check.perform(state)
|
assert ^state = @check.perform(state)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -156,7 +157,7 @@ defmodule Plausible.Verification.Checks.SnippetTest do
|
||||||
[data_domain: "example.com"]
|
[data_domain: "example.com"]
|
||||||
|> Keyword.merge(opts)
|
|> Keyword.merge(opts)
|
||||||
|
|
||||||
State
|
@default_state
|
||||||
|> struct!(opts)
|
|> struct!(opts)
|
||||||
|> State.assign(document: doc)
|
|> State.assign(document: doc)
|
||||||
end
|
end
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
defmodule Plausible.Verification.ChecksTest do
|
defmodule Plausible.InstallationSupport.LegacyVerification.ChecksTest do
|
||||||
use Plausible.DataCase, async: true
|
use Plausible.DataCase, async: true
|
||||||
|
|
||||||
alias Plausible.Verification.Checks
|
alias Plausible.InstallationSupport.{State, Checks, LegacyVerification}
|
||||||
alias Plausible.Verification.Diagnostics
|
|
||||||
alias Plausible.Verification.State
|
|
||||||
|
|
||||||
import ExUnit.CaptureLog
|
import ExUnit.CaptureLog
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
@errors Plausible.Verification.Errors.all()
|
@errors LegacyVerification.Errors.all()
|
||||||
|
|
||||||
describe "successful verification" do
|
describe "successful verification" do
|
||||||
@normal_body """
|
@normal_body """
|
||||||
|
|
@ -25,7 +23,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -33,7 +31,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
ref = :counters.new(1, [:atomics])
|
ref = :counters.new(1, [:atomics])
|
||||||
test = self()
|
test = self()
|
||||||
|
|
||||||
Req.Test.stub(Plausible.Verification.Checks.FetchBody, fn conn ->
|
Req.Test.stub(Checks.FetchBody, fn conn ->
|
||||||
if :counters.get(ref, 1) < 2 do
|
if :counters.get(ref, 1) < 2 do
|
||||||
:counters.add(ref, 1, 1)
|
:counters.add(ref, 1, 1)
|
||||||
send(test, :redirect_sent)
|
send(test, :redirect_sent)
|
||||||
|
|
@ -51,7 +49,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
|
|
||||||
assert_receive :redirect_sent
|
assert_receive :redirect_sent
|
||||||
|
|
@ -76,7 +74,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -94,7 +92,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -107,7 +105,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, 202))
|
stub_installation(200, plausible_installed(true, 202))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -124,7 +122,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
ref = :counters.new(1, [:atomics])
|
ref = :counters.new(1, [:atomics])
|
||||||
test = self()
|
test = self()
|
||||||
|
|
||||||
Req.Test.stub(Plausible.Verification.Checks.FetchBody, fn conn ->
|
Req.Test.stub(Checks.FetchBody, fn conn ->
|
||||||
if :counters.get(ref, 1) == 0 do
|
if :counters.get(ref, 1) == 0 do
|
||||||
:counters.add(ref, 1, 1)
|
:counters.add(ref, 1, 1)
|
||||||
send(test, :redirect_sent)
|
send(test, :redirect_sent)
|
||||||
|
|
@ -142,7 +140,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
|
|
||||||
assert_receive :redirect_sent
|
assert_receive :redirect_sent
|
||||||
|
|
@ -155,7 +153,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(400, %{})
|
stub_installation(400, %{})
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.temporary)
|
|> assert_error(@errors.temporary)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -167,7 +165,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
{_, log} =
|
{_, log} =
|
||||||
with_log(fn ->
|
with_log(fn ->
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
@ -190,7 +188,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.unreachable, url: "https://example.com")
|
|> assert_error(@errors.unreachable, url: "https://example.com")
|
||||||
|
|
||||||
assert_receive :redirect_sent
|
assert_receive :redirect_sent
|
||||||
|
|
@ -217,7 +215,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.snippet_in_body)
|
|> assert_error(@errors.snippet_in_body)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -242,7 +240,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.multiple_snippets)
|
|> assert_error(@errors.multiple_snippets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -262,7 +260,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.no_snippet)
|
|> assert_error(@errors.no_snippet)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -283,7 +281,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_ok()
|
|> assert_ok()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -315,7 +313,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.cache_general)
|
|> assert_error(@errors.cache_general)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -357,7 +355,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.cache_wp_no_plugin)
|
|> assert_error(@errors.cache_wp_no_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -400,7 +398,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.cache_wp_plugin)
|
|> assert_error(@errors.cache_wp_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -409,7 +407,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.no_snippet)
|
|> assert_error(@errors.no_snippet)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -429,13 +427,13 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.no_snippet_wp)
|
|> assert_error(@errors.no_snippet_wp)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "a check that raises" do
|
test "a check that raises" do
|
||||||
defmodule FaultyCheckRaise do
|
defmodule FaultyCheckRaise do
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "Faulty check"
|
def report_progress_as, do: "Faulty check"
|
||||||
|
|
@ -450,16 +448,16 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert log =~
|
assert log =~
|
||||||
~s|Error running check Plausible.Verification.ChecksTest.FaultyCheckRaise on https://example.com: %RuntimeError{message: "boom"}|
|
~s|Error running check Plausible.InstallationSupport.LegacyVerification.ChecksTest.FaultyCheckRaise on https://example.com: %RuntimeError{message: "boom"}|
|
||||||
|
|
||||||
result
|
result
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.unreachable, url: "https://example.com")
|
|> assert_error(@errors.unreachable, url: "https://example.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "a check that throws" do
|
test "a check that throws" do
|
||||||
defmodule FaultyCheckThrow do
|
defmodule FaultyCheckThrow do
|
||||||
use Plausible.Verification.Check
|
use Plausible.InstallationSupport.Check
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def report_progress_as, do: "Faulty check"
|
def report_progress_as, do: "Faulty check"
|
||||||
|
|
@ -474,10 +472,10 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert log =~
|
assert log =~
|
||||||
~s|Error running check Plausible.Verification.ChecksTest.FaultyCheckThrow on https://example.com: :boom|
|
~s|Error running check Plausible.InstallationSupport.LegacyVerification.ChecksTest.FaultyCheckThrow on https://example.com: :boom|
|
||||||
|
|
||||||
result
|
result
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.unreachable, url: "https://example.com")
|
|> assert_error(@errors.unreachable, url: "https://example.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -492,7 +490,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.csp)
|
|> assert_error(@errors.csp)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -507,7 +505,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.no_snippet)
|
|> assert_error(@errors.no_snippet)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -517,13 +515,15 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
|
|
||||||
final_state = run_checks(report_to: self())
|
final_state = run_checks(report_to: self())
|
||||||
|
|
||||||
assert_receive {:verification_check_start, {Checks.FetchBody, %State{}}}
|
assert_receive {:check_start, {Checks.FetchBody, %State{}}}
|
||||||
assert_receive {:verification_check_start, {Checks.CSP, %State{}}}
|
assert_receive {:check_start, {Checks.CSP, %State{}}}
|
||||||
assert_receive {:verification_check_start, {Checks.ScanBody, %State{}}}
|
assert_receive {:check_start, {Checks.ScanBody, %State{}}}
|
||||||
assert_receive {:verification_check_start, {Checks.Snippet, %State{}}}
|
assert_receive {:check_start, {Checks.Snippet, %State{}}}
|
||||||
assert_receive {:verification_check_start, {Checks.SnippetCacheBust, %State{}}}
|
|
||||||
assert_receive {:verification_check_start, {Checks.Installation, %State{}}}
|
assert_receive {:check_start, {Checks.SnippetCacheBust, %State{}}}
|
||||||
assert_receive {:verification_end, %State{} = ^final_state}
|
|
||||||
|
assert_receive {:check_start, {Checks.Installation, %State{}}}
|
||||||
|
assert_receive {:all_checks_done, %State{} = ^final_state}
|
||||||
refute_receive _
|
refute_receive _
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -555,7 +555,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.csp)
|
|> assert_error(@errors.csp)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -564,7 +564,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.gtm)
|
|> assert_error(@errors.gtm)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -591,7 +591,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.gtm_cookie_banner)
|
|> assert_error(@errors.gtm_cookie_banner)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -605,7 +605,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false))
|
stub_installation(200, plausible_installed(false))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.unreachable, url: "https://example.com")
|
|> assert_error(@errors.unreachable, url: "https://example.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -614,7 +614,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, 0))
|
stub_installation(200, plausible_installed(true, 0))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.proxy_misconfigured)
|
|> assert_error(@errors.proxy_misconfigured)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -633,7 +633,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false, 0))
|
stub_installation(200, plausible_installed(false, 0))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.proxy_wp_no_plugin)
|
|> assert_error(@errors.proxy_wp_no_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -642,13 +642,13 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false, 0))
|
stub_installation(200, plausible_installed(false, 0))
|
||||||
|
|
||||||
result = run_checks()
|
result = run_checks()
|
||||||
interpretation = Checks.interpret_diagnostics(result)
|
interpretation = LegacyVerification.Checks.interpret_diagnostics(result)
|
||||||
|
|
||||||
refute interpretation.ok?
|
refute interpretation.ok?
|
||||||
assert interpretation.errors == ["We encountered an error with your Plausible proxy"]
|
assert interpretation.errors == ["We encountered an error with your Plausible proxy"]
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.proxy_general)
|
|> assert_error(@errors.proxy_general)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -657,7 +657,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, 0))
|
stub_installation(200, plausible_installed(true, 0))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.unknown)
|
|> assert_error(@errors.unknown)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -675,7 +675,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false, 0))
|
stub_installation(200, plausible_installed(false, 0))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.illegal_attrs_general)
|
|> assert_error(@errors.illegal_attrs_general)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -694,7 +694,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false, 0))
|
stub_installation(200, plausible_installed(false, 0))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.illegal_attrs_wp_no_plugin)
|
|> assert_error(@errors.illegal_attrs_wp_no_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -714,7 +714,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(false, 0))
|
stub_installation(200, plausible_installed(false, 0))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.illegal_attrs_wp_plugin)
|
|> assert_error(@errors.illegal_attrs_wp_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -723,7 +723,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, -1))
|
stub_installation(200, plausible_installed(true, -1))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.generic)
|
|> assert_error(@errors.generic)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -732,7 +732,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, -1))
|
stub_installation(200, plausible_installed(true, -1))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.old_script_wp_no_plugin)
|
|> assert_error(@errors.old_script_wp_no_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -741,7 +741,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, -1))
|
stub_installation(200, plausible_installed(true, -1))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.old_script_wp_plugin)
|
|> assert_error(@errors.old_script_wp_plugin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -750,7 +750,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation(200, plausible_installed(true, 500))
|
stub_installation(200, plausible_installed(true, 500))
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.unknown)
|
|> assert_error(@errors.unknown)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -759,7 +759,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.different_data_domain, domain: "example.com")
|
|> assert_error(@errors.different_data_domain, domain: "example.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -780,14 +780,14 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
stub_installation()
|
stub_installation()
|
||||||
|
|
||||||
run_checks()
|
run_checks()
|
||||||
|> Checks.interpret_diagnostics()
|
|> LegacyVerification.Checks.interpret_diagnostics()
|
||||||
|> assert_error(@errors.different_data_domain, domain: "example.com")
|
|> assert_error(@errors.different_data_domain, domain: "example.com")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "unhhandled cases from sentry" do
|
describe "unhhandled cases from sentry" do
|
||||||
test "APP-58: 4b1435e3f8a048eb949cc78fa578d1e4" do
|
test "APP-58: 4b1435e3f8a048eb949cc78fa578d1e4" do
|
||||||
%Plausible.Verification.Diagnostics{
|
%LegacyVerification.Diagnostics{
|
||||||
plausible_installed?: true,
|
plausible_installed?: true,
|
||||||
snippets_found_in_head: 0,
|
snippets_found_in_head: 0,
|
||||||
snippets_found_in_body: 0,
|
snippets_found_in_body: 0,
|
||||||
|
|
@ -810,7 +810,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "service timeout" do
|
test "service timeout" do
|
||||||
%Plausible.Verification.Diagnostics{
|
%LegacyVerification.Diagnostics{
|
||||||
plausible_installed?: false,
|
plausible_installed?: false,
|
||||||
snippets_found_in_head: 1,
|
snippets_found_in_head: 1,
|
||||||
snippets_found_in_body: 0,
|
snippets_found_in_body: 0,
|
||||||
|
|
@ -833,7 +833,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "malformed snippet code, that headless somewhat accepts" do
|
test "malformed snippet code, that headless somewhat accepts" do
|
||||||
%Plausible.Verification.Diagnostics{
|
%LegacyVerification.Diagnostics{
|
||||||
plausible_installed?: true,
|
plausible_installed?: true,
|
||||||
snippets_found_in_head: 0,
|
snippets_found_in_head: 0,
|
||||||
snippets_found_in_body: 0,
|
snippets_found_in_body: 0,
|
||||||
|
|
@ -856,7 +856,7 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "gtm+wp detected, but likely script id attribute interfering" do
|
test "gtm+wp detected, but likely script id attribute interfering" do
|
||||||
%Plausible.Verification.Diagnostics{
|
%LegacyVerification.Diagnostics{
|
||||||
plausible_installed?: false,
|
plausible_installed?: false,
|
||||||
snippets_found_in_head: 1,
|
snippets_found_in_head: 1,
|
||||||
snippets_found_in_body: 0,
|
snippets_found_in_body: 0,
|
||||||
|
|
@ -881,12 +881,12 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
|
|
||||||
defp interpret_sentry_case(diagnostics) do
|
defp interpret_sentry_case(diagnostics) do
|
||||||
diagnostics
|
diagnostics
|
||||||
|> Diagnostics.interpret("example.com")
|
|> LegacyVerification.Diagnostics.interpret("example.com")
|
||||||
|> refute_unhandled()
|
|> refute_unhandled()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp run_checks(extra_opts \\ []) do
|
defp run_checks(extra_opts \\ []) do
|
||||||
Checks.run(
|
LegacyVerification.Checks.run(
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
"example.com",
|
"example.com",
|
||||||
Keyword.merge([async?: false, report_to: nil, slowdown: 0], extra_opts)
|
Keyword.merge([async?: false, report_to: nil, slowdown: 0], extra_opts)
|
||||||
|
|
@ -894,11 +894,11 @@ defmodule Plausible.Verification.ChecksTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(f) when is_function(f, 1) do
|
defp stub_fetch_body(f) when is_function(f, 1) do
|
||||||
Req.Test.stub(Plausible.Verification.Checks.FetchBody, f)
|
Req.Test.stub(Checks.FetchBody, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_installation(f) when is_function(f, 1) do
|
defp stub_installation(f) when is_function(f, 1) do
|
||||||
Req.Test.stub(Plausible.Verification.Checks.Installation, f)
|
Req.Test.stub(Checks.Installation, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(status, body) do
|
defp stub_fetch_body(status, body) do
|
||||||
|
|
@ -3,6 +3,8 @@ defmodule PlausibleWeb.Live.Components.VerificationTest do
|
||||||
import Phoenix.LiveViewTest, only: [render_component: 2]
|
import Phoenix.LiveViewTest, only: [render_component: 2]
|
||||||
import Plausible.Test.Support.HTML
|
import Plausible.Test.Support.HTML
|
||||||
|
|
||||||
|
alias Plausible.InstallationSupport.{State, LegacyVerification}
|
||||||
|
|
||||||
@component PlausibleWeb.Live.Components.Verification
|
@component PlausibleWeb.Live.Components.Verification
|
||||||
@progress ~s|#progress-indicator p#progress|
|
@progress ~s|#progress-indicator p#progress|
|
||||||
|
|
||||||
|
|
@ -36,8 +38,9 @@ defmodule PlausibleWeb.Live.Components.VerificationTest do
|
||||||
|
|
||||||
test "renders diagnostic interpretation" do
|
test "renders diagnostic interpretation" do
|
||||||
interpretation =
|
interpretation =
|
||||||
Plausible.Verification.Checks.interpret_diagnostics(%Plausible.Verification.State{
|
LegacyVerification.Checks.interpret_diagnostics(%State{
|
||||||
url: "example.com"
|
url: "example.com",
|
||||||
|
diagnostics: %LegacyVerification.Diagnostics{}
|
||||||
})
|
})
|
||||||
|
|
||||||
html =
|
html =
|
||||||
|
|
@ -58,12 +61,13 @@ defmodule PlausibleWeb.Live.Components.VerificationTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renders super-admin report" do
|
test "renders super-admin report" do
|
||||||
state = %Plausible.Verification.State{
|
state = %State{
|
||||||
url: "example.com"
|
url: "example.com",
|
||||||
|
diagnostics: %LegacyVerification.Diagnostics{}
|
||||||
}
|
}
|
||||||
|
|
||||||
interpretation =
|
interpretation =
|
||||||
Plausible.Verification.Checks.interpret_diagnostics(state)
|
LegacyVerification.Checks.interpret_diagnostics(state)
|
||||||
|
|
||||||
html =
|
html =
|
||||||
render_component(@component,
|
render_component(@component,
|
||||||
|
|
|
||||||
|
|
@ -355,7 +355,7 @@ defmodule PlausibleWeb.Live.InstallationTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(f) when is_function(f, 1) do
|
defp stub_fetch_body(f) when is_function(f, 1) do
|
||||||
Req.Test.stub(Plausible.Verification.Checks.FetchBody, f)
|
Req.Test.stub(Plausible.InstallationSupport.Checks.FetchBody, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(status, body) do
|
defp stub_fetch_body(status, body) do
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ defmodule PlausibleWeb.Live.InstallationV2Test do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(f) when is_function(f, 1) do
|
defp stub_fetch_body(f) when is_function(f, 1) do
|
||||||
Req.Test.stub(Plausible.Verification.Checks.FetchBody, f)
|
Req.Test.stub(Plausible.InstallationSupport.Checks.FetchBody, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(status, body) do
|
defp stub_fetch_body(status, body) do
|
||||||
|
|
|
||||||
|
|
@ -184,11 +184,11 @@ defmodule PlausibleWeb.Live.VerificationTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(f) when is_function(f, 1) do
|
defp stub_fetch_body(f) when is_function(f, 1) do
|
||||||
Req.Test.stub(Plausible.Verification.Checks.FetchBody, f)
|
Req.Test.stub(Plausible.InstallationSupport.Checks.FetchBody, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_installation(f) when is_function(f, 1) do
|
defp stub_installation(f) when is_function(f, 1) do
|
||||||
Req.Test.stub(Plausible.Verification.Checks.Installation, f)
|
Req.Test.stub(Plausible.InstallationSupport.Checks.Installation, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stub_fetch_body(status, body) do
|
defp stub_fetch_body(status, body) do
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,16 @@
|
||||||
This document describes the design goals informing the architecture of the Plausible tracker script codebase as well as a map
|
This document describes the design goals informing the architecture of the Plausible tracker script codebase as well as a map
|
||||||
to how the code is laid out.
|
to how the code is laid out.
|
||||||
|
|
||||||
|
## Installation Support
|
||||||
|
|
||||||
|
The tracker subdirectory also includes site verification and pre-installation checks that are run in headless browser, via
|
||||||
|
browserless.io. These files live under the `/tracker/installation-support/` director and are meant to provide Plausible
|
||||||
|
installation support - checking the site for what technologies to recommend and verifying whether Plausible has been
|
||||||
|
installed correctly. Please see `lib/plausible/installation_support/checks/installation.ex` for the Elixir context and how
|
||||||
|
this JS code ends up being used.
|
||||||
|
|
||||||
|
While this logic could be separated from the tracker script, it's convenient for installation support to reuse the Playwright test structure and JS compilation logic without introducing yet another subdirectory with its own dependencies.
|
||||||
|
|
||||||
## Design goals
|
## Design goals
|
||||||
|
|
||||||
We want to provide users a javascript suite to capture page views and activities done on the web page.
|
We want to provide users a javascript suite to capture page views and activities done on the web page.
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,16 @@
|
||||||
},
|
},
|
||||||
"npm_package": "esm"
|
"npm_package": "esm"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "detector.js",
|
||||||
|
"entry_point": "installation_support/detector.js",
|
||||||
|
"output_path": "priv/tracker/installation_support/detector.js",
|
||||||
|
"globals": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "verifier-v1.js",
|
"name": "verifier-v1.js",
|
||||||
"entry_point": "verifier/verifier-v1.js",
|
"entry_point": "installation_support/verifier-v1.js",
|
||||||
"output_path": "priv/tracker/verifier/verifier-v1.js",
|
"output_path": "priv/tracker/installation_support/verifier-v1.js",
|
||||||
"globals": {}
|
"globals": {}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { waitForSnippetsV1 } from "./snippet-checks"
|
||||||
|
import { checkWordPress } from "./check-wordpress"
|
||||||
|
import { checkGTM } from "./check-gtm"
|
||||||
|
|
||||||
|
window.scanPageBeforePlausibleInstallation = async function(detectV1, debug) {
|
||||||
|
function log(message) {
|
||||||
|
if (debug) console.log('[Plausible Verification]', message)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {wordpressPlugin, wordpressLikely} = checkWordPress(document)
|
||||||
|
log(`wordpressPlugin: ${wordpressPlugin}`)
|
||||||
|
log(`wordpressLikely: ${wordpressLikely}`)
|
||||||
|
|
||||||
|
const gtmLikely = checkGTM(document)
|
||||||
|
log(`gtmLikely: ${gtmLikely}`)
|
||||||
|
|
||||||
|
// Cannot implement yet: we should detect the WP plugin version here and
|
||||||
|
// decide `v1Detected` based on that. For now we assume WP plugin is v1.
|
||||||
|
let v1Detected = wordpressPlugin
|
||||||
|
|
||||||
|
if (!v1Detected && detectV1) {
|
||||||
|
const snippetData = await waitForSnippetsV1(log)
|
||||||
|
v1Detected = snippetData.counts.all > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
completed: true,
|
||||||
|
v1Detected: v1Detected,
|
||||||
|
wordpressPlugin: wordpressPlugin,
|
||||||
|
wordpressLikely: wordpressLikely,
|
||||||
|
gtmLikely: gtmLikely,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,7 +15,11 @@ export default defineConfig({
|
||||||
retries: process.env.CI ? 1 : 0,
|
retries: process.env.CI ? 1 : 0,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'list',
|
reporter: 'list',
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/*
|
||||||
|
Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions.
|
||||||
|
NOTE: We run the installation support tests on Chrome only because the Browserless /function API
|
||||||
|
runs a Chromium-based browser environment.
|
||||||
|
*/
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
name: 'chromium',
|
name: 'chromium',
|
||||||
|
|
@ -25,13 +29,13 @@ export default defineConfig({
|
||||||
{
|
{
|
||||||
name: 'firefox',
|
name: 'firefox',
|
||||||
use: { ...devices['Desktop Firefox'] },
|
use: { ...devices['Desktop Firefox'] },
|
||||||
testIgnore: 'test/verifier/**',
|
testIgnore: 'test/installation_support/**',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'webkit',
|
name: 'webkit',
|
||||||
use: { ...devices['Desktop Safari'] },
|
use: { ...devices['Desktop Safari'] },
|
||||||
testIgnore: 'test/verifier/**',
|
testIgnore: 'test/installation_support/**',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
webServer: {
|
webServer: {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { checkDataDomainMismatch } from '../../verifier/check-data-domain-mismatch'
|
import { checkDataDomainMismatch } from '../../installation_support/check-data-domain-mismatch'
|
||||||
|
|
||||||
function mockSnippet(dataDomain) {
|
function mockSnippet(dataDomain) {
|
||||||
return { getAttribute: _ => dataDomain }
|
return { getAttribute: _ => dataDomain }
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { checkGTM } from '../../verifier/check-gtm'
|
import { checkGTM } from '../../installation_support/check-gtm'
|
||||||
|
|
||||||
function mockDocument(html) {
|
function mockDocument(html) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { checkManualExtension } from '../../verifier/check-manual-extension'
|
import { checkManualExtension } from '../../installation_support/check-manual-extension'
|
||||||
|
|
||||||
function mockSnippet(dataDomain) {
|
function mockSnippet(dataDomain) {
|
||||||
return { getAttribute: _ => dataDomain }
|
return { getAttribute: _ => dataDomain }
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { checkProxyLikely } from '../../verifier/check-proxy-likely'
|
import { checkProxyLikely } from '../../installation_support/check-proxy-likely'
|
||||||
|
|
||||||
function mockSnippet(src) {
|
function mockSnippet(src) {
|
||||||
return { getAttribute: _ => src }
|
return { getAttribute: _ => src }
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { checkUnknownAttributes } from '../../verifier/check-unknown-attributes.js'
|
import { checkUnknownAttributes } from '../../installation_support/check-unknown-attributes.js'
|
||||||
|
|
||||||
test.describe('checkUnknownAttributes', () => {
|
test.describe('checkUnknownAttributes', () => {
|
||||||
test('returns false when no snippets', () => {
|
test('returns false when no snippets', () => {
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { checkWordPress, WORDPRESS_PLUGIN_VERSION_SELECTOR } from '../../verifier/check-wordpress'
|
import { checkWordPress, WORDPRESS_PLUGIN_VERSION_SELECTOR } from '../../installation_support/check-wordpress'
|
||||||
|
|
||||||
function mockDocument(html, hasMetaTag) {
|
function mockDocument(html, hasMetaTag) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
import { detect } from '../support/installation-support-playwright-wrappers'
|
||||||
|
import { initializePageDynamically } from '../support/initialize-page-dynamically'
|
||||||
|
|
||||||
|
test.describe('detector.js (basic diagnostics)', () => {
|
||||||
|
test('skips v1 snippet detection by default', async ({ page }, { testId }) => {
|
||||||
|
const { url } = await initializePageDynamically(page, {
|
||||||
|
testId,
|
||||||
|
response: `
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="" data-domain=""></script>
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = await detect(page, {url: url, detectV1: false})
|
||||||
|
|
||||||
|
expect(result.data.v1Detected).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('detects WP plugin, WP and GTM', async ({ page }, { testId }) => {
|
||||||
|
const { url } = await initializePageDynamically(page, {
|
||||||
|
testId,
|
||||||
|
response: `
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="icon" href="https://example.com/wp-content/uploads/favicon.ico" sizes="32x32">
|
||||||
|
<meta name="plausible-analytics-version" content="2.3.1">
|
||||||
|
<script async src="https://www.googletagmanager.com/gtm.js?id=GTM-123"></script>
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = await detect(page, {url: url, detectV1: false})
|
||||||
|
|
||||||
|
expect(result.data.wordpressPlugin).toBe(true)
|
||||||
|
expect(result.data.wordpressLikely).toBe(true)
|
||||||
|
expect(result.data.gtmLikely).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('No WP plugin, WP or GTM', async ({ page }, { testId }) => {
|
||||||
|
const { url } = await initializePageDynamically(page, {
|
||||||
|
testId,
|
||||||
|
response: '<html><head></head></html>'
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = await detect(page, {url: url, detectV1: false})
|
||||||
|
|
||||||
|
expect(result.data.wordpressPlugin).toBe(false)
|
||||||
|
expect(result.data.wordpressLikely).toBe(false)
|
||||||
|
expect(result.data.gtmLikely).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import verify from '../support/verify-playwright-wrapper'
|
import { verify } from '../support/installation-support-playwright-wrappers'
|
||||||
import { delay } from '../support/test-utils'
|
import { delay } from '../support/test-utils'
|
||||||
import { initializePageDynamically } from '../support/initialize-page-dynamically'
|
import { initializePageDynamically } from '../support/initialize-page-dynamically'
|
||||||
import { compileFile } from '../../compiler'
|
import { compileFile } from '../../compiler'
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { compileFile } from '../../compiler/index.js'
|
||||||
|
import variantsFile from '../../compiler/variants.json' with { type: 'json' }
|
||||||
|
|
||||||
|
const VERIFIER_V1_JS_VARIANT = variantsFile.manualVariants.find(variant => variant.name === 'verifier-v1.js')
|
||||||
|
const DETECTOR_JS_VARIANT = variantsFile.manualVariants.find(variant => variant.name === 'detector.js')
|
||||||
|
|
||||||
|
export async function verify(page, context) {
|
||||||
|
const {url, expectedDataDomain} = context
|
||||||
|
const debug = context.debug ? true : false
|
||||||
|
|
||||||
|
const verifierCode = await compileFile(VERIFIER_V1_JS_VARIANT, { returnCode: true })
|
||||||
|
|
||||||
|
await page.goto(url)
|
||||||
|
await page.evaluate(verifierCode)
|
||||||
|
|
||||||
|
return await page.evaluate(async ({expectedDataDomain, debug}) => {
|
||||||
|
return await window.verifyPlausibleInstallation(expectedDataDomain, debug)
|
||||||
|
}, {expectedDataDomain, debug})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function detect(page, context) {
|
||||||
|
const {url, detectV1} = context
|
||||||
|
const debug = context.debug ? true : false
|
||||||
|
|
||||||
|
const detectorCode = await compileFile(DETECTOR_JS_VARIANT, { returnCode: true })
|
||||||
|
|
||||||
|
await page.goto(url)
|
||||||
|
await page.evaluate(detectorCode)
|
||||||
|
|
||||||
|
return await page.evaluate(async ({detectV1, debug}) => {
|
||||||
|
return await window.scanPageBeforePlausibleInstallation(detectV1, debug)
|
||||||
|
}, {detectV1, debug})
|
||||||
|
}
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { compileFile } from '../../compiler/index.js'
|
|
||||||
import variantsFile from '../../compiler/variants.json' with { type: 'json' }
|
|
||||||
|
|
||||||
const VARIANT = variantsFile.manualVariants.find(variant => variant.name === 'verifier-v1.js')
|
|
||||||
|
|
||||||
export default async function verify(page, context) {
|
|
||||||
const {url, expectedDataDomain} = context
|
|
||||||
const debug = context.debug ? true : false
|
|
||||||
|
|
||||||
const verifierCode = await compileFile(VARIANT, { returnCode: true })
|
|
||||||
|
|
||||||
await page.goto(url)
|
|
||||||
await page.evaluate(verifierCode)
|
|
||||||
|
|
||||||
return await page.evaluate(async ({expectedDataDomain, debug}) => {
|
|
||||||
return await window.verifyPlausibleInstallation(expectedDataDomain, debug)
|
|
||||||
}, {expectedDataDomain, debug})
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue