forked from rails/rails
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request rails#53065 from larouxn/add_active_support_notifi…
…cations_event_assertions Add `ActiveSupport::Testing::NotificationAssertions` test helper module
- Loading branch information
Showing
4 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
activesupport/lib/active_support/testing/notification_assertions.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
|
||
# typed: true | ||
# frozen_string_literal: true | ||
|
||
module ActiveSupport | ||
module Testing | ||
module NotificationAssertions | ||
# Assert a notification was emitted with a given +pattern+ and optional +payload+. | ||
# | ||
# You can assert that a notification was emitted by passing a pattern, which accepts | ||
# either a string or regexp, an optional payload, and a block. While the block | ||
# is executed, if a matching notification is emitted, the assertion will pass. | ||
# | ||
# assert_notification("post.submitted", title: "Cool Post") do | ||
# post.submit(title: "Cool Post") # => emits matching notification | ||
# end | ||
# | ||
def assert_notification(pattern, payload = nil, &block) | ||
notifications = capture_notifications(pattern, &block) | ||
assert_not_empty(notifications, "No #{pattern} notifications were found") | ||
|
||
return if payload.nil? | ||
|
||
notification = notifications.find { |notification| notification.payload == payload } | ||
assert_not_nil(notification, "No #{pattern} notification with payload #{payload} was found") | ||
end | ||
|
||
# Assert the number of notifications emitted with a given +pattern+. | ||
# | ||
# You can assert the number of notifications emitted by passing a pattern, which accepts | ||
# either a string or regexp, a count, and a block. While the block is executed, | ||
# the number of matching notifications emitted will be counted. After the block's | ||
# execution completes, the assertion will pass if the count matches. | ||
# | ||
# assert_notifications_count("post.submitted", 1) do | ||
# post.submit(title: "Cool Post") # => emits matching notification | ||
# end | ||
# | ||
def assert_notifications_count(pattern, count, &block) | ||
actual_count = capture_notifications(pattern, &block).count | ||
assert_equal(count, actual_count, "Expected #{count} instead of #{actual_count} notifications for #{pattern}") | ||
end | ||
|
||
# Assert no notifications were emitted for a given +pattern+. | ||
# | ||
# You can assert no notifications were emitted by passing a pattern, which accepts | ||
# either a string or regexp, and a block. While the block is executed, if no | ||
# matching notifications are emitted, the assertion will pass. | ||
# | ||
# assert_no_notifications("post.submitted") do | ||
# post.destroy # => emits non-matching notification | ||
# end | ||
# | ||
def assert_no_notifications(pattern = nil, &block) | ||
notifications = capture_notifications(pattern, &block) | ||
error_message = if pattern | ||
"Expected no notifications for #{pattern} but found #{notifications.size}" | ||
else | ||
"Expected no notifications but found #{notifications.size}" | ||
end | ||
assert_empty(notifications, error_message) | ||
end | ||
|
||
# Capture emitted notifications, optionally filtered by a +pattern+. | ||
# | ||
# You can capture emitted notifications, optionally filtered by a pattern, | ||
# which accepts either a string or regexp, and a block. | ||
# | ||
# notifications = capture_notifications("post.submitted") do | ||
# post.submit(title: "Cool Post") # => emits matching notification | ||
# end | ||
# | ||
def capture_notifications(pattern = nil, &block) | ||
notifications = [] | ||
ActiveSupport::Notifications.subscribed(->(n) { notifications << n }, pattern, &block) | ||
notifications | ||
end | ||
end | ||
end | ||
end |
100 changes: 100 additions & 0 deletions
100
activesupport/test/testing/notification_assertions_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "../abstract_unit" | ||
require "active_support/testing/notification_assertions" | ||
|
||
module ActiveSupport | ||
module Testing | ||
class NotificationAssertionsTest < ActiveSupport::TestCase | ||
include NotificationAssertions | ||
|
||
def test_assert_notification | ||
assert_notification("post.submitted", title: "Cool Post") do | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
|
||
assert_notification("post.submitted") do # payload omitted | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
|
||
assert_raises(Minitest::Assertion, match: /No post.submitted notifications were found/) do | ||
assert_notification("post.submitted", title: "Cool Post") { nil } # no notifications | ||
end | ||
|
||
match = if RUBY_VERSION >= "3.4" | ||
/No post.submitted notification with payload {title: "Cool Post"} was found/ | ||
else | ||
/No post.submitted notification with payload {:title=>"Cool Post"} was found/ | ||
end | ||
assert_raises(Minitest::Assertion, match:) do | ||
assert_notification("post.submitted", title: "Cool Post") do | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cooler Post") | ||
end | ||
end | ||
end | ||
|
||
def test_assert_notifications_count | ||
assert_notifications_count("post.submitted", 1) do | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
|
||
assert_raises(Minitest::Assertion, match: /Expected 1 instead of 2 notifications for post.submitted/) do | ||
assert_notifications_count("post.submitted", 1) do | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cooler Post") | ||
end | ||
end | ||
|
||
assert_raises(Minitest::Assertion, match: /Expected 1 instead of 0 notifications for post.submitted/) do | ||
assert_notifications_count("post.submitted", 1) { nil } # no notifications | ||
end | ||
end | ||
|
||
def test_assert_no_notifications | ||
assert_no_notifications("post.submitted") { nil } # no notifications | ||
|
||
assert_raises(Minitest::Assertion, match: /Expected no notifications for post.submitted but found 1/) do | ||
assert_no_notifications("post.submitted") do | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
end | ||
|
||
assert_raises(Minitest::Assertion, match: /Expected no notifications but found 1/) do | ||
assert_no_notifications do | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
end | ||
end | ||
|
||
def test_capture_notifications | ||
notifications = capture_notifications("post.submitted") do # string pattern | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
|
||
assert_equal(1, notifications.size) | ||
assert_equal("post.submitted", notifications.first.name) | ||
assert_equal({ title: "Cool Post" }, notifications.first.payload) | ||
|
||
notifications = capture_notifications(/post\./) do # regexp pattern | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
|
||
assert_equal(1, notifications.size) | ||
assert_equal("post.submitted", notifications.first.name) | ||
assert_equal({ title: "Cool Post" }, notifications.first.payload) | ||
|
||
notifications = capture_notifications do # no pattern | ||
ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post") | ||
end | ||
|
||
assert_equal(1, notifications.size) | ||
assert_equal("post.submitted", notifications.first.name) | ||
assert_equal({ title: "Cool Post" }, notifications.first.payload) | ||
|
||
notifications = capture_notifications("post.submitted") { nil } # no notifications | ||
|
||
assert_empty(notifications) | ||
end | ||
end | ||
end | ||
end |