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, user_id: 123, timestamp: Timex.shift(now, days: -7), referrer_source: "Google" ), 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