Files
fizzy/test/models/notification/bundle_test.rb
T
Stanko Krtalić eceb6c9b43 Add self-service account deletion (#2246)
* Add self-service account deletion

* Disable access to cancelled accounts & implement Stripe interactions

* Add tests

* Fix failing tests

* Remove cancelled accounts from lists

* Fix incorrect redirect

* Use _path instead of _url for consistency

* Don't track how far the inicieration job got

We still want the step tracking so that the job can be interrupted. But, since the scope is idempotent, we don't need to track how far it got.

* Specify the exact time when the data will be deleted

* Fix crash due to unadvancable cursor

* Rename up_for_incineration to due_for_incineration

* Regenrate the schema

* Fix incorrect path check

* Migrate the SQLite schema

* Only show the cancel button on cancellable accounts

* Check that a subscirption method exists before calling it

* Ignore job failures due to missing records when an account gets deleted

* Skip sending notifications on cancelled accounts

* Use collbacks to integrate

* Add a blank line between queue_as and discard_on

* Break checks into methods

* Inline methods

* Rename Account::IncinerateJob

* Run migrations

* Migrate SQLite
2026-01-12 14:21:05 +01:00

181 lines
5.8 KiB
Ruby

require "test_helper"
class Notification::BundleTest < ActiveSupport::TestCase
include ActionMailer::TestHelper
setup do
@user = users(:david)
@user.settings.bundle_email_every_few_hours!
end
test "new notifications are bundled" do
notification = assert_difference -> { @user.notification_bundles.pending.count }, 1 do
@user.notifications.create!(source: events(:logo_published), creator: @user)
end
bundle = @user.notification_bundles.pending.last
assert_includes bundle.notifications, notification
end
test "don't bundle new notifications if bundling is disabled" do
@user.settings.bundle_email_never!
assert_no_difference -> { @user.notification_bundles.count } do
@user.notifications.create!(source: events(:logo_published), creator: @user)
end
end
test "notifications are bundled withing the aggregation period" do
@user.notification_bundles.destroy_all
notification_1 = assert_difference -> { @user.notification_bundles.pending.count }, 1 do
@user.notifications.create!(source: events(:logo_published), creator: @user)
end
travel_to 3.hours.from_now
notification_2 = assert_no_difference -> { @user.notification_bundles.count } do
@user.notifications.create!(source: events(:logo_published), creator: @user)
end
travel_to 3.days.from_now
notification_3 = assert_difference -> { @user.notification_bundles.pending.count }, 1 do
@user.notifications.create!(source: events(:logo_published), creator: @user)
end
assert_equal 2, @user.notification_bundles.count
bundle_1, bundle_2 = @user.notification_bundles.all.to_a
assert_includes bundle_1.notifications, notification_1
assert_includes bundle_1.notifications, notification_2
assert_includes bundle_2.notifications, notification_3
end
test "overlapping bundles are invalid" do
bundle_1 = @user.notification_bundles.create!(
starts_at: Time.current,
ends_at: 4.hours.from_now,
status: :pending
)
bundle_2 = @user.notification_bundles.build(
starts_at: 2.hours.from_now,
ends_at: 6.hours.from_now,
status: :pending
)
assert_not bundle_2.valid?
# Bundle with overlapping end time should be invalid
bundle_3 = @user.notification_bundles.build(
starts_at: 2.hours.ago,
ends_at: 2.hours.from_now,
status: :pending
)
assert_not bundle_3.valid?
# Bundle completely within another bundle should be invalid
bundle_4 = @user.notification_bundles.build(
starts_at: 1.hour.from_now,
ends_at: 3.hours.from_now,
status: :pending
)
assert_not bundle_4.valid?
# Non-overlapping bundle should be valid
bundle_5 = @user.notification_bundles.build(
starts_at: 5.hours.from_now,
ends_at: 9.hours.from_now,
status: :pending
)
assert bundle_5.valid?
end
test "overlapping bundles that are created relying on set_default_window are not created" do
@user.notification_bundles.destroy_all
bundle = @user.notification_bundles.create!(starts_at: Time.current)
assert_raises ActiveRecord::RecordInvalid do
@user.notification_bundles.create!(starts_at: bundle.starts_at - 1.second)
end
end
test "deliver_all delivers due bundles" do
@user.notification_bundles.destroy_all
notification = @user.notifications.create!(source: events(:logo_published), creator: @user)
bundle = @user.notification_bundles.pending.last
assert bundle.pending?
assert_includes bundle.notifications, notification
bundle.update!(ends_at: 1.minute.ago)
perform_enqueued_jobs only: Notification::Bundle::DeliverJob do
Notification::Bundle.deliver_all
end
bundle.reload
assert bundle.delivered?
end
test "deliver_all don't deliver bundles that are not due" do
@user.notifications.create!(source: events(:logo_published), creator: @user)
bundle = @user.notification_bundles.pending.last
bundle.update!(ends_at: 1.minute.from_now)
perform_enqueued_jobs only: Notification::Bundle::DeliverJob do
Notification::Bundle.deliver_all
end
bundle.reload
assert bundle.pending?
end
test "deliver sends email with time in user's time zone" do
@user.settings.update!(timezone_name: "Madrid")
freeze_time Time.utc(2025, 1, 15, 14, 30, 0) do
@user.notifications.create!(source: events(:logo_published), creator: @user)
bundle = @user.notification_bundles.pending.last
bundle.deliver
email = ActionMailer::Base.deliveries.last
assert_not_nil email
# Time in Madrid should be 15:30 (UTC+1 in winter)
assert_match /notifications since 3pm/i, email.text_part&.body&.to_s
end
end
test "out-of-order notification bundling should still work" do
first_notification = @user.notifications.create!(source: events(:logo_published), creator: @user)
second_notification = @user.notifications.create!(source: events(:logo_published), creator: @user)
@user.notification_bundles.destroy_all
assert first_notification.created_at < second_notification.created_at
@user.bundle(second_notification)
@user.bundle(first_notification)
assert_equal 1, @user.notification_bundles.pending.count
assert_equal 2, @user.notification_bundles.last.notifications.count
assert_includes @user.notification_bundles.last.notifications, first_notification
assert_includes @user.notification_bundles.last.notifications, second_notification
end
test "deliver does not send email for cancelled accounts" do
@user.notifications.create!(source: events(:logo_published), creator: @user)
bundle = @user.notification_bundles.pending.last
@user.account.cancel(initiated_by: @user)
assert_no_emails do
deliver_enqueued_emails do
bundle.deliver
end
end
assert bundle.delivered?, "Bundle should be marked as delivered even if not sent"
end
end