analytics/test/workers/send_email_report_test.exs
RobertJoonas d2270f3c35
Small bugfix + refactor email reports (#3642)
* use more convenient testing functions

* do not display + sign with 0% change in emails

* Rename module/file/function names

before, `weekly_report` was also used for monthly reports and that was a
bit confusing to read in code.

* Refactor send_email_report.ex

This commit improves readability by refactoring the code into smaller
functions and reducing the number of arguments given to functions.

But more importantly, it stops making duplicate stats queries for every
email recipient by moving the queries out of the for loop.

* Refactor: move querying logic out of the worker module

and merge all stats information under a single `stats` assign.
2023-12-21 12:56:06 +00:00

234 lines
8.7 KiB
Elixir

defmodule Plausible.Workers.SendEmailReportTest do
use Plausible.DataCase
use Bamboo.Test
use Oban.Testing, repo: Plausible.Repo
import Plausible.Test.Support.HTML
alias Plausible.Workers.SendEmailReport
alias Timex.Timezone
@green "#15803d"
@red "#b91c1c"
describe "weekly reports" do
test "sends weekly report to all recipients" do
site = insert(:site, domain: "test-site.com", timezone: "US/Eastern")
insert(:weekly_report, site: site, recipients: ["user@email.com", "user2@email.com"])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
assert_email_delivered_with(
subject: "Weekly report for #{site.domain}",
to: [nil: "user@email.com"]
)
assert_email_delivered_with(
subject: "Weekly report for #{site.domain}",
to: [nil: "user2@email.com"]
)
end
test "does not crash for deleted sites" do
assert :discard =
perform_job(SendEmailReport, %{"site_id" => 28_378_237, "interval" => "weekly"})
end
test "calculates timezone correctly" do
site =
insert(:site,
timezone: "US/Eastern"
)
insert(:weekly_report, site: site, recipients: ["user@email.com"])
now = Timex.now(site.timezone)
last_monday = Timex.shift(now, weeks: -1) |> Timex.beginning_of_week()
last_sunday = Timex.shift(now, weeks: -1) |> Timex.end_of_week()
sunday_before_last = Timex.shift(last_monday, minutes: -1)
this_monday = Timex.beginning_of_week(now)
create_pageviews([
# Sunday before last, not counted
%{site: site, timestamp: Timezone.convert(sunday_before_last, "UTC")},
# Sunday before last, not counted
%{site: site, timestamp: Timezone.convert(sunday_before_last, "UTC")},
# Last monday, counted
%{site: site, timestamp: Timezone.convert(last_monday, "UTC")},
# Last sunday, counted
%{site: site, timestamp: Timezone.convert(last_sunday, "UTC")},
# This monday, not counted
%{site: site, timestamp: Timezone.convert(this_monday, "UTC")},
# This monday, not counted
%{site: site, timestamp: Timezone.convert(this_monday, "UTC")}
])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
assert_delivered_email_matches(%{
to: [nil: "user@email.com"],
html_body: html_body
})
# Should find 2 visiors
assert text_of_element(html_body, ".page-count") == "2"
end
test "includes the correct stats" do
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
site = insert(:site, domain: "test-site.com", inserted_at: Timex.shift(now, days: -8))
insert(:weekly_report, site: site, recipients: ["user@email.com"])
populate_stats(site, [
build(:pageview,
referrer_source: "Google",
user_id: 123,
timestamp: Timex.shift(now, days: -7)
),
build(:pageview, user_id: 123, timestamp: Timex.shift(now, days: -7)),
build(:pageview, timestamp: Timex.shift(now, days: -7))
])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
assert_delivered_email_matches(%{
to: [nil: "user@email.com"],
html_body: html_body
})
assert text_of_element(html_body, ".visitors") == "2"
assert text_of_element(html_body, ".pageviews") == "3"
assert text_of_element(html_body, ".referrer-name") == "Google"
assert text_of_element(html_body, ".referrer-count") == "1"
assert text_of_element(html_body, ".page-name") == "/"
assert text_of_element(html_body, ".page-count") == "2"
end
test "renders correct signs (+/-) and trend colors for positive percentage changes" do
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
week_ago = now |> Timex.shift(days: -7)
two_weeks_ago = now |> Timex.shift(days: -14)
site = insert(:site, inserted_at: Timex.shift(now, days: -15))
insert(:weekly_report, site: site, recipients: ["user@email.com"])
populate_stats(site, [
build(:pageview, timestamp: two_weeks_ago),
build(:pageview, user_id: 1, timestamp: week_ago),
build(:pageview, user_id: 2, timestamp: week_ago),
build(:pageview, user_id: 2, timestamp: week_ago)
])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
assert_delivered_email_matches(%{
to: [nil: "user@email.com"],
html_body: html_body
})
visitors_change_container = find(html_body, ".change-visitors div")
assert text(visitors_change_container) == "+100%"
assert text_of_attr(visitors_change_container, "style") =~ @green
pageviews_change_container = find(html_body, ".change-pageviews div")
assert text(pageviews_change_container) == "+200%"
assert text_of_attr(pageviews_change_container, "style") =~ @green
bounce_rate_change_container = find(html_body, ".change-bounce-rate div")
assert text(bounce_rate_change_container) == "-50%"
assert text_of_attr(bounce_rate_change_container, "style") =~ @green
end
test "renders correct signs (+/-) and trend colors for negative percentage changes" do
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
week_ago = now |> Timex.shift(days: -7)
two_weeks_ago = now |> Timex.shift(days: -14)
site = insert(:site, inserted_at: Timex.shift(now, days: -15))
insert(:weekly_report, site: site, recipients: ["user@email.com"])
populate_stats(site, [
build(:pageview, user_id: 1, timestamp: two_weeks_ago),
build(:pageview, user_id: 2, timestamp: two_weeks_ago),
build(:pageview, user_id: 2, timestamp: two_weeks_ago),
build(:pageview, timestamp: week_ago)
])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
assert_delivered_email_matches(%{
to: [nil: "user@email.com"],
html_body: html_body
})
visitors_change_container = find(html_body, ".change-visitors div")
assert text(visitors_change_container) == "-50%"
assert text_of_attr(visitors_change_container, "style") =~ @red
pageviews_change_container = find(html_body, ".change-pageviews div")
assert text(pageviews_change_container) == "-67%"
assert text_of_attr(pageviews_change_container, "style") =~ @red
bounce_rate_change_container = find(html_body, ".change-bounce-rate div")
assert text(bounce_rate_change_container) == "+50%"
assert text_of_attr(bounce_rate_change_container, "style") =~ @red
end
test "renders 0% changes with a green color and without a sign" do
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
week_ago = now |> Timex.shift(days: -7)
two_weeks_ago = now |> Timex.shift(days: -14)
site = insert(:site, inserted_at: Timex.shift(now, days: -15))
insert(:weekly_report, site: site, recipients: ["user@email.com"])
populate_stats(site, [
build(:pageview, timestamp: two_weeks_ago),
build(:pageview, timestamp: week_ago)
])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
assert_delivered_email_matches(%{
to: [nil: "user@email.com"],
html_body: html_body
})
visitors_change_container = find(html_body, ".change-visitors div")
assert text(visitors_change_container) == "0%"
assert text_of_attr(visitors_change_container, "style") =~ @green
pageviews_change_container = find(html_body, ".change-pageviews div")
assert text(pageviews_change_container) == "0%"
assert text_of_attr(pageviews_change_container, "style") =~ @green
bounce_rate_change_container = find(html_body, ".change-bounce-rate div")
assert text(bounce_rate_change_container) == "0%"
assert text_of_attr(bounce_rate_change_container, "style") =~ @green
end
end
describe "monthly_reports" do
test "sends monthly report to all recipients" do
site = insert(:site, domain: "test-site.com", timezone: "US/Eastern")
insert(:monthly_report, site: site, recipients: ["user@email.com", "user2@email.com"])
last_month =
Timex.now(site.timezone)
|> Timex.shift(months: -1)
|> Timex.beginning_of_month()
|> Timex.format!("{Mfull}")
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "monthly"})
assert_email_delivered_with(
subject: "#{last_month} report for #{site.domain}",
to: [nil: "user@email.com"]
)
assert_email_delivered_with(
subject: "#{last_month} report for #{site.domain}",
to: [nil: "user2@email.com"]
)
end
end
end