485 lines
17 KiB
Elixir
485 lines
17 KiB
Elixir
defmodule PlausibleWeb.EmailTest do
|
|
use Plausible.DataCase, async: true
|
|
|
|
import Plausible.Factory
|
|
|
|
alias PlausibleWeb.Email
|
|
|
|
describe "base_email layout" do
|
|
test "greets user by first name if user in template assigns" do
|
|
email =
|
|
Email.base_email()
|
|
|> Email.render("welcome_email.html", %{
|
|
user: build(:user, name: "John Doe"),
|
|
code: "123"
|
|
})
|
|
|
|
assert email.html_body =~ "Hey John,"
|
|
assert email.text_body =~ "Hey John,"
|
|
end
|
|
|
|
test "greets impersonally when user not in template assigns" do
|
|
email =
|
|
Email.base_email()
|
|
|> Email.render("welcome_email.html")
|
|
|
|
assert email.html_body =~ "Hey,"
|
|
assert email.text_body =~ "Hey,"
|
|
end
|
|
|
|
test "renders plausible link" do
|
|
email =
|
|
Email.base_email()
|
|
|> Email.render("welcome_email.html")
|
|
|
|
assert email.html_body =~ plausible_link()
|
|
assert email.text_body =~ plausible_url()
|
|
end
|
|
|
|
@tag :ee_only
|
|
test "renders unsubscribe placeholder" do
|
|
email =
|
|
Email.base_email()
|
|
|> Email.render("welcome_email.html")
|
|
|
|
assert email.html_body =~ "{{{ pm:unsubscribe }}}"
|
|
end
|
|
|
|
test "can be disabled with a nil layout" do
|
|
email =
|
|
Email.base_email(%{layout: nil})
|
|
|> Email.render("welcome_email.html", %{
|
|
user: build(:user, name: "John Doe")
|
|
})
|
|
|
|
refute email.html_body =~ "Hey John,"
|
|
refute email.html_body =~ plausible_link()
|
|
|
|
refute email.text_body =~ "Hey John,"
|
|
refute email.text_body =~ plausible_url()
|
|
end
|
|
end
|
|
|
|
describe "priority email layout" do
|
|
@tag :ee_only
|
|
test "uses the `priority` message stream in Postmark in EE" do
|
|
email =
|
|
Email.priority_email()
|
|
|> Email.render("activation_email.html", %{
|
|
user: build(:user, name: "John Doe"),
|
|
code: "123"
|
|
})
|
|
|
|
assert %{"MessageStream" => "priority"} = email.private[:message_params]
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "doesn't use the `priority` message stream in Postmark in CE" do
|
|
email =
|
|
Email.priority_email()
|
|
|> Email.render("activation_email.html", %{
|
|
user: build(:user, name: "John Doe"),
|
|
code: "123"
|
|
})
|
|
|
|
refute email.private[:message_params]["MessageStream"]
|
|
end
|
|
|
|
test "greets user by first name if user in template assigns" do
|
|
email =
|
|
Email.priority_email()
|
|
|> Email.render("activation_email.html", %{
|
|
user: build(:user, name: "John Doe"),
|
|
code: "123"
|
|
})
|
|
|
|
assert email.html_body =~ "Hey John,"
|
|
assert email.text_body =~ "Hey John,"
|
|
end
|
|
|
|
test "greets impersonally when user not in template assigns" do
|
|
email =
|
|
Email.priority_email()
|
|
|> Email.render("password_reset_email.html", %{
|
|
reset_link: "imaginary"
|
|
})
|
|
|
|
assert email.html_body =~ "Hey,"
|
|
assert email.text_body =~ "Hey,"
|
|
end
|
|
|
|
test "renders plausible link" do
|
|
email =
|
|
Email.priority_email()
|
|
|> Email.render("password_reset_email.html", %{
|
|
reset_link: "imaginary"
|
|
})
|
|
|
|
assert email.html_body =~ plausible_link()
|
|
assert email.text_body =~ plausible_url()
|
|
end
|
|
|
|
test "does not render unsubscribe placeholder" do
|
|
email =
|
|
Email.priority_email()
|
|
|> Email.render("password_reset_email.html", %{
|
|
reset_link: "imaginary"
|
|
})
|
|
|
|
refute email.html_body =~ "{{{ pm:unsubscribe }}}"
|
|
end
|
|
|
|
test "can be disabled with a nil layout" do
|
|
email =
|
|
Email.priority_email(%{layout: nil})
|
|
|> Email.render("password_reset_email.html", %{
|
|
reset_link: "imaginary"
|
|
})
|
|
|
|
refute email.html_body =~ "Hey John,"
|
|
refute email.html_body =~ plausible_link()
|
|
|
|
refute email.text_body =~ "Hey John,"
|
|
refute email.text_body =~ plausible_url()
|
|
end
|
|
end
|
|
|
|
describe "over_limit_email/3" do
|
|
test "renders usage, suggested plan, and links to upgrade and account settings" do
|
|
user = build(:user)
|
|
team = build(:team, identifier: Ecto.UUID.generate())
|
|
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
|
|
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
|
|
|
|
usage = %{
|
|
penultimate_cycle: %{date_range: penultimate_cycle, total: 12_300},
|
|
last_cycle: %{date_range: last_cycle, total: 32_100}
|
|
}
|
|
|
|
%{html_body: html_body, subject: subject} =
|
|
PlausibleWeb.Email.over_limit_email(user, team, usage, "100k")
|
|
|
|
assert subject == "[Action required] You have outgrown your Plausible subscription tier"
|
|
|
|
assert html_body =~ PlausibleWeb.TextHelpers.format_date_range(last_cycle)
|
|
assert html_body =~ "We recommend you upgrade to the 100k pageviews/month plan"
|
|
assert html_body =~ "your account recorded 32,100 billable pageviews"
|
|
|
|
assert html_body =~
|
|
"cycle before that (#{PlausibleWeb.TextHelpers.format_date_range(penultimate_cycle)}), your account used 12,300 billable pageviews"
|
|
|
|
assert text_of_element(
|
|
html_body,
|
|
~s|a[href$="/billing/choose-plan?__team=#{team.identifier}"]|
|
|
) ==
|
|
"Click here to upgrade your subscription"
|
|
|
|
assert text_of_element(
|
|
html_body,
|
|
~s|a[href$="/settings/billing/subscription?__team=#{team.identifier}"]|
|
|
) ==
|
|
"account settings"
|
|
|
|
assert html_body =~
|
|
PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <>
|
|
"?__team=#{team.identifier}"
|
|
end
|
|
|
|
test "asks enterprise level usage to contact us" do
|
|
user = build(:user)
|
|
team = build(:team, identifier: Ecto.UUID.generate())
|
|
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
|
|
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
|
|
suggested_plan = :enterprise
|
|
|
|
usage = %{
|
|
penultimate_cycle: %{date_range: penultimate_cycle, total: 12_300},
|
|
last_cycle: %{date_range: last_cycle, total: 32_100}
|
|
}
|
|
|
|
%{html_body: html_body} =
|
|
PlausibleWeb.Email.over_limit_email(user, team, usage, suggested_plan)
|
|
|
|
refute html_body =~ "Click here to upgrade your subscription"
|
|
assert html_body =~ "Your usage exceeds our standard plans, so please reply back"
|
|
end
|
|
end
|
|
|
|
describe "dashboard_locked/3" do
|
|
test "renders usage, suggested plan, and links to upgrade and account settings" do
|
|
user = build(:user)
|
|
team = build(:team, identifier: Ecto.UUID.generate())
|
|
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
|
|
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
|
|
|
|
usage = %{
|
|
penultimate_cycle: %{date_range: penultimate_cycle, total: 12_300},
|
|
last_cycle: %{date_range: last_cycle, total: 32_100}
|
|
}
|
|
|
|
%{html_body: html_body, subject: subject} =
|
|
PlausibleWeb.Email.dashboard_locked(user, team, usage, "100k")
|
|
|
|
assert subject == "[Action required] Your Plausible dashboard is now locked"
|
|
|
|
assert html_body =~ PlausibleWeb.TextHelpers.format_date_range(last_cycle)
|
|
assert html_body =~ "We recommend you upgrade to the 100k pageviews/month plan"
|
|
assert html_body =~ "your account recorded 32,100 billable pageviews"
|
|
|
|
assert html_body =~
|
|
"cycle before that (#{PlausibleWeb.TextHelpers.format_date_range(penultimate_cycle)}), the usage was 12,300 billable pageviews"
|
|
|
|
assert text_of_element(
|
|
html_body,
|
|
~s|a[href$="/billing/choose-plan?__team=#{team.identifier}"]|
|
|
) ==
|
|
"Click here to upgrade your subscription"
|
|
|
|
assert text_of_element(
|
|
html_body,
|
|
~s|a[href$="/settings/billing/subscription?__team=#{team.identifier}"]|
|
|
) ==
|
|
"account settings"
|
|
|
|
assert html_body =~
|
|
PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <>
|
|
"?__team=#{team.identifier}"
|
|
end
|
|
|
|
test "asks enterprise level usage to contact us" do
|
|
user = build(:user)
|
|
team = build(:team, identifier: Ecto.UUID.generate())
|
|
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
|
|
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
|
|
suggested_plan = :enterprise
|
|
|
|
usage = %{
|
|
penultimate_cycle: %{date_range: penultimate_cycle, total: 12_300},
|
|
last_cycle: %{date_range: last_cycle, total: 32_100}
|
|
}
|
|
|
|
%{html_body: html_body} =
|
|
PlausibleWeb.Email.dashboard_locked(user, team, usage, suggested_plan)
|
|
|
|
refute html_body =~ "Click here to upgrade your subscription"
|
|
assert html_body =~ "Your usage exceeds our standard plans, so please reply back"
|
|
end
|
|
end
|
|
|
|
describe "enterprise_over_limit_internal_email/4" do
|
|
test "renders pageview usage by billing cycles + sites usage/limit" do
|
|
user = build(:user)
|
|
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
|
|
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
|
|
|
|
pageview_usage = %{
|
|
penultimate_cycle: %{date_range: penultimate_cycle, total: 100_141_888},
|
|
last_cycle: %{date_range: last_cycle, total: 100_222_999}
|
|
}
|
|
|
|
%{html_body: html_body, subject: subject} =
|
|
PlausibleWeb.Email.enterprise_over_limit_internal_email(user, pageview_usage, 80, 50)
|
|
|
|
assert subject == "#{user.email} has outgrown their enterprise plan"
|
|
|
|
assert html_body =~
|
|
"Last billing cycle: #{PlausibleWeb.TextHelpers.format_date_range(last_cycle)}"
|
|
|
|
assert html_body =~ "Last cycle pageview usage: 100,222,999 billable pageviews"
|
|
|
|
assert html_body =~
|
|
"Penultimate billing cycle: #{PlausibleWeb.TextHelpers.format_date_range(penultimate_cycle)}"
|
|
|
|
assert html_body =~ "Penultimate cycle pageview usage: 100,141,888 billable pageviews"
|
|
assert html_body =~ "Site usage: 80 / 50 allowed sites"
|
|
end
|
|
end
|
|
|
|
describe "approaching accept_traffic_until" do
|
|
test "renders first warning" do
|
|
user = build(:user, id: 123, name: "John Doe")
|
|
team = build(:team, identifier: Ecto.UUID.generate())
|
|
|
|
notification = %{
|
|
id: user.id,
|
|
email: user.email,
|
|
deadline: Date.add(Date.utc_today(), 7),
|
|
site_ids: [1, 2, 3],
|
|
name: user.name,
|
|
team: team
|
|
}
|
|
|
|
%{html_body: body, subject: subject} =
|
|
PlausibleWeb.Email.approaching_accept_traffic_until(notification)
|
|
|
|
assert subject == "We'll stop counting your stats"
|
|
assert body =~ plausible_link(team: team, label: "login to your Plausible account")
|
|
assert body =~ "Hey John,"
|
|
|
|
assert body =~
|
|
"We've noticed that you're still sending us stats so we're writing to inform you that we'll stop accepting stats from your sites next week."
|
|
end
|
|
|
|
test "renders final warning" do
|
|
user = build(:user, id: 123, name: "John Doe")
|
|
team = build(:team, identifier: Ecto.UUID.generate())
|
|
|
|
notification = %{
|
|
id: user.id,
|
|
email: user.email,
|
|
deadline: Date.add(Date.utc_today(), 1),
|
|
site_ids: [1, 2, 3],
|
|
name: user.name,
|
|
team: team
|
|
}
|
|
|
|
%{html_body: body, subject: subject} =
|
|
PlausibleWeb.Email.approaching_accept_traffic_until_tomorrow(notification)
|
|
|
|
assert subject == "A reminder that we'll stop counting your stats tomorrow"
|
|
assert body =~ plausible_link(team: team, label: "login to your Plausible account")
|
|
|
|
assert body =~
|
|
"We've noticed that you're still sending us stats so we're writing to inform you that we'll stop accepting stats from your sites tomorrow."
|
|
end
|
|
end
|
|
|
|
describe "site setup emails" do
|
|
setup do
|
|
trial_user = new_user(trial_expiry_date: Date.add(Date.utc_today(), 100))
|
|
site = new_site(owner: trial_user)
|
|
|
|
emails = [
|
|
PlausibleWeb.Email.create_site_email(trial_user),
|
|
PlausibleWeb.Email.site_setup_help(trial_user, site.team, site),
|
|
PlausibleWeb.Email.site_setup_success(trial_user, site.team, site)
|
|
]
|
|
|
|
{:ok, emails: emails}
|
|
end
|
|
|
|
@trial_message "trial"
|
|
@reply_message "reply back"
|
|
|
|
@tag :ee_only
|
|
test "has 'trial' and 'reply' blocks, correct product name", %{emails: emails} do
|
|
for email <- emails do
|
|
assert email.html_body =~ @trial_message
|
|
assert email.html_body =~ @reply_message
|
|
refute email.html_body =~ "Plausible CE"
|
|
end
|
|
|
|
assert Enum.any?(emails, fn email -> email.html_body =~ "Plausible Analytics" end)
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "no 'trial' or 'reply' blocks, correct product name", %{emails: emails} do
|
|
for email <- emails do
|
|
refute email.html_body =~ @trial_message
|
|
refute email.html_body =~ @reply_message
|
|
refute email.html_body =~ "Plausible Analytics"
|
|
end
|
|
|
|
assert Enum.any?(emails, fn email -> email.html_body =~ "Plausible CE" end)
|
|
end
|
|
end
|
|
|
|
describe "text_body" do
|
|
@tag :ee_only
|
|
test "welcome_email (EE)" do
|
|
email =
|
|
Email.base_email()
|
|
|> Email.render("welcome_email.html", %{
|
|
user: build(:user, name: "John Doe"),
|
|
code: "123"
|
|
})
|
|
|
|
assert email.text_body == """
|
|
Hey John,
|
|
|
|
We are building Plausible to provide a simple and ethical approach to tracking website visitors. We're super excited to have you on board!
|
|
|
|
Here's how to get the most out of your Plausible experience:
|
|
|
|
* Enable email reports (https://plausible.io/docs/email-reports) and notifications for traffic spikes (https://plausible.io/docs/traffic-spikes)
|
|
* Integrate with Search Console (https://plausible.io/docs/google-search-console-integration) to get keyword phrases people find your site with
|
|
* Invite team members and other collaborators (https://plausible.io/docs/users-roles)
|
|
* Set up easy goals including form submissions (https://plausible.io/docs/form-submissions-tracking), 404 error pages (https://plausible.io/docs/error-pages-tracking-404), file downloads (https://plausible.io/docs/file-downloads-tracking) and outbound link clicks (https://plausible.io/docs/outbound-link-click-tracking)
|
|
* Opt out from counting your own visits (https://plausible.io/docs/excluding)
|
|
* If you're concerned about adblockers, set up a proxy to bypass them (https://plausible.io/docs/proxy/introduction)
|
|
|
|
|
|
Then you're ready to start exploring your fast loading, ethical and actionable Plausible dashboard (https://plausible.io/sites).
|
|
|
|
Have a question, feedback or need some guidance? Do reply back to this email.
|
|
|
|
Regards,
|
|
The Plausible Team 💌
|
|
|
|
--
|
|
|
|
http://localhost:8000
|
|
{{{ pm:unsubscribe }}}\
|
|
"""
|
|
end
|
|
|
|
@tag :ce_build_only
|
|
test "welcome_email (CE)" do
|
|
email =
|
|
Email.base_email()
|
|
|> Email.render("welcome_email.html", %{
|
|
user: build(:user, name: "John Doe"),
|
|
code: "123"
|
|
})
|
|
|
|
assert email.text_body == """
|
|
Hey John,
|
|
|
|
We are building Plausible to provide a simple and ethical approach to tracking website visitors. We're super excited to have you on board!
|
|
|
|
Here's how to get the most out of your Plausible experience:
|
|
|
|
* Enable email reports (https://plausible.io/docs/email-reports) and notifications for traffic spikes (https://plausible.io/docs/traffic-spikes)
|
|
* Integrate with Search Console (https://plausible.io/docs/google-search-console-integration) to get keyword phrases people find your site with
|
|
* Invite team members and other collaborators (https://plausible.io/docs/users-roles)
|
|
* Set up easy goals including form submissions (https://plausible.io/docs/form-submissions-tracking), 404 error pages (https://plausible.io/docs/error-pages-tracking-404), file downloads (https://plausible.io/docs/file-downloads-tracking) and outbound link clicks (https://plausible.io/docs/outbound-link-click-tracking)
|
|
* Opt out from counting your own visits (https://plausible.io/docs/excluding)
|
|
* If you're concerned about adblockers, set up a proxy to bypass them (https://plausible.io/docs/proxy/introduction)
|
|
|
|
|
|
Then you're ready to start exploring your fast loading, ethical and actionable Plausible dashboard (https://plausible.io/sites).
|
|
|
|
Have a question, feedback or need some guidance? Do reply back to this email.
|
|
|
|
--
|
|
|
|
http://localhost:8000
|
|
"""
|
|
end
|
|
end
|
|
|
|
def plausible_url do
|
|
PlausibleWeb.EmailView.plausible_url()
|
|
end
|
|
|
|
def plausible_link(opts \\ []) do
|
|
suffix =
|
|
if team = Keyword.get(opts, :team) do
|
|
"?__team=#{team.identifier}"
|
|
else
|
|
""
|
|
end
|
|
|
|
plausible_url = plausible_url()
|
|
|
|
label =
|
|
if label = Keyword.get(opts, :label) do
|
|
label
|
|
else
|
|
plausible_url
|
|
end
|
|
|
|
"<a href=\"#{plausible_url <> suffix}\">#{label}</a>"
|
|
end
|
|
end
|