Skip to content

Introduce have_reported_error matcher #2849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5e6efcc
first pass at have_reported_error matcher
skatkov Jun 4, 2025
5dd2c5c
Adding a feature
skatkov Jun 7, 2025
ce1a162
simplify matcher/readmer.md
skatkov Jun 14, 2025
550c25e
Remove mocks out of tests
skatkov Jun 14, 2025
e074991
test failure messages better
skatkov Jun 14, 2025
1fe7e91
rewrite specs
skatkov Jun 20, 2025
6b41d2b
should require a block matcher
skatkov Jun 22, 2025
3859b04
Create ErrorEvent struct to store errors
skatkov Jun 22, 2025
8352668
simplify matcher
skatkov Jun 22, 2025
030c27a
disable matcher chaining
skatkov Jun 22, 2025
2b9bd02
improved argument error message in case block is not passed to matcher
skatkov Jun 22, 2025
6135d5d
further clean-up
skatkov Jun 22, 2025
8335664
Apply suggestions from code review
skatkov Jun 25, 2025
a14f5c7
clean-up features
skatkov Jun 27, 2025
af58d83
remove a require from test
skatkov Jul 1, 2025
7259a25
rename .with to .with_context
skatkov Jul 1, 2025
1b6deb6
have_reported_error to accept class name and a message
skatkov Jul 1, 2025
c77fca5
switch to error_report matcher type of api
skatkov Jul 1, 2025
f5e427a
refactor
skatkov Jul 1, 2025
7b3abc5
Using UndefinedValue as a default attribute
skatkov Jul 1, 2025
2488a71
Look through all errors, don't just go with last error
skatkov Jul 1, 2025
c1816e2
warn about nil being passed
skatkov Jul 9, 2025
e1ab316
Use ErrorCollector from Rails instead of self-written version'
Aug 4, 2025
8674529
Use defined UNDEFINED value instead of defining our own
Aug 4, 2025
8b89342
Update features/matchers/README.md
pirj Aug 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions lib/rspec/rails/matchers/have_reported_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
module RSpec
module Rails
module Matchers
# @api private
# Sentinel value to distinguish between no argument passed vs explicitly passed nil.
# This follows the same pattern as RSpec's raise_error matcher.
UndefinedValue = Object.new.freeze

# @api private
class ErrorSubscriber
attr_reader :events
Expand All @@ -28,17 +33,20 @@ def report(error, **attrs)
class HaveReportedError < RSpec::Rails::Matchers::BaseMatcher
# Initialize the matcher following raise_error patterns
#
# Uses UndefinedValue as default to distinguish between no argument
# passed vs explicitly passed nil (same as raise_error matcher).
#
# @param expected_error_or_message [Class, String, Regexp, nil]
# Error class, message string, or message pattern
# @param expected_message [String, Regexp, nil]
# Expected message when first param is a class
def initialize(expected_error_or_message = nil, expected_message = nil)
def initialize(expected_error_or_message = UndefinedValue, expected_message = nil)
@actual_error = nil
@attributes = {}
@error_subscriber = nil

case expected_error_or_message
when nil
when nil, UndefinedValue
@expected_error = nil
@expected_message = expected_message
when String, Regexp
Expand Down Expand Up @@ -232,7 +240,7 @@ def unmatched_attributes(actual)
#
# @param expected_error_or_message [Class, String, Regexp, nil] the expected error class, message string, or message pattern
# @param expected_message [String, Regexp, nil] the expected error message to match
def have_reported_error(expected_error_or_message = nil, expected_message = nil)
def have_reported_error(expected_error_or_message = UndefinedValue, expected_message = nil)
HaveReportedError.new(expected_error_or_message, expected_message)
end

Expand Down
10 changes: 10 additions & 0 deletions spec/rspec/rails/matchers/have_reported_error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,22 @@ class AnotherTestError < StandardError; end
expect {Rails.error.report(StandardError.new("test error"))}.to have_reported_error
end

it "passes when an error is reported with explicit nil argument" do
expect {Rails.error.report(StandardError.new("test error"))}.to have_reported_error(nil)
end

it "fails when no errors are reported" do
expect {
expect { "no error" }.to have_reported_error
}.to fail_with(/Expected the block to report an error, but none was reported./)
end

it "fails when no errors are reported with explicit nil argument" do
expect {
expect { "no error" }.to have_reported_error(nil)
}.to fail_with(/Expected the block to report an error, but none was reported./)
end

it "passes when negated and no errors are reported" do
expect { "no error" }.not_to have_reported_error
end
Expand Down