Skip to content

Commit f5e427a

Browse files
committed
refactor
1 parent c77fca5 commit f5e427a

File tree

2 files changed

+45
-27
lines changed

2 files changed

+45
-27
lines changed

lib/rspec/rails/matchers/have_reported_error.rb

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,34 @@ def report(error, **attrs)
2020

2121
# Matcher class for `have_reported_error`. Should not be instantiated directly.
2222
#
23+
# Provides a way to test that an error was reported to Rails.error.
24+
# This matcher follows the same patterns as RSpec's built-in `raise_error` matcher.
25+
#
2326
# @api private
2427
# @see RSpec::Rails::Matchers#have_reported_error
2528
class HaveReportedError < RSpec::Rails::Matchers::BaseMatcher
29+
# Initialize the matcher following raise_error patterns
30+
#
31+
# @param expected_error_or_message [Class, String, Regexp, nil]
32+
# Error class, message string, or message pattern
33+
# @param expected_message [String, Regexp, nil]
34+
# Expected message when first param is a class
2635
def initialize(expected_error_or_message = nil, expected_message = nil)
27-
if expected_error_or_message.is_a?(Regexp)
28-
@expected_error_class = nil
29-
@expected_message = expected_error_or_message
30-
elsif expected_error_or_message.is_a?(String)
31-
@expected_error_class = nil
36+
@actual_error = nil
37+
@attributes = {}
38+
@error_subscriber = nil
39+
40+
case expected_error_or_message
41+
when nil
42+
@expected_error = nil
43+
@expected_message = expected_message
44+
when String, Regexp
45+
@expected_error = nil
3246
@expected_message = expected_error_or_message
3347
else
34-
@expected_error_class = expected_error_or_message
48+
@expected_error = expected_error_or_message
3549
@expected_message = expected_message
3650
end
37-
38-
@attributes = {}
39-
@error_subscriber = nil
4051
end
4152

4253
def with_context(expected_attributes)
@@ -48,9 +59,10 @@ def and(_)
4859
raise ArgumentError, "Chaining is not supported"
4960
end
5061

62+
# Check if the block reports an error matching our expectations
5163
def matches?(block)
5264
if block.nil?
53-
raise ArgumentError, "this matcher doesnt work with value expectations"
65+
raise ArgumentError, "this matcher doesn't work with value expectations"
5466
end
5567

5668
@error_subscriber = ErrorSubscriber.new
@@ -71,8 +83,8 @@ def supports_block_expectations?
7183
end
7284

7385
def description
74-
base_desc = if @expected_error_class
75-
"report a #{@expected_error_class} error"
86+
base_desc = if @expected_error
87+
"report a #{@expected_error} error"
7688
else
7789
"report an error"
7890
end
@@ -103,8 +115,8 @@ def failure_message
103115
elsif @error_subscriber.events.empty?
104116
return 'Expected the block to report an error, but none was reported.'
105117
else
106-
if @expected_error_class && !actual_error.is_a?(@expected_error_class)
107-
return "Expected error to be an instance of #{@expected_error_class}, but got #{actual_error.class} with message: '#{actual_error.message}'"
118+
if @expected_error && !actual_error.is_a?(@expected_error)
119+
return "Expected error to be an instance of #{@expected_error}, but got #{actual_error.class} with message: '#{actual_error.message}'"
108120
elsif @expected_message
109121
case @expected_message
110122
when Regexp
@@ -128,26 +140,31 @@ def failure_message_when_negated
128140

129141
private
130142

143+
# Check if the reported error matches our class and message expectations
131144
def error_matches_expectation?
132-
# If no events were reported, we can't match anything
133145
return false if @error_subscriber.events.empty?
134-
135-
# If no constraints are given, any error should match
136-
return true if @expected_error_class.nil? && @expected_message.nil?
146+
return true if @expected_error.nil? && @expected_message.nil?
147+
148+
error_class_matches? && error_message_matches?
149+
end
137150

138-
class_matches = @expected_error_class.nil? || actual_error.is_a?(@expected_error_class)
151+
# Check if the actual error class matches the expected error class
152+
def error_class_matches?
153+
@expected_error.nil? || actual_error.is_a?(@expected_error)
154+
end
155+
156+
# Check if the actual error message matches the expected message pattern
157+
def error_message_matches?
158+
return true if @expected_message.nil?
139159

140-
message_matches = if @expected_message.nil?
141-
true
142-
elsif @expected_message.is_a?(Regexp)
160+
case @expected_message
161+
when Regexp
143162
actual_error.message&.match(@expected_message)
144-
elsif @expected_message.is_a?(String)
163+
when String
145164
actual_error.message == @expected_message
146165
else
147166
false
148167
end
149-
150-
class_matches && message_matches
151168
end
152169

153170
def attributes_match_if_specified?
@@ -158,8 +175,9 @@ def attributes_match_if_specified?
158175
attributes_match?(event_context)
159176
end
160177

178+
# Get the actual error that was reported (cached)
161179
def actual_error
162-
@error_subscriber.events.empty? ? nil : @error_subscriber.events.last.error
180+
@actual_error ||= (@error_subscriber.events.empty? ? nil : @error_subscriber.events.last.error)
163181
end
164182

165183
def attributes_match?(actual)

spec/rspec/rails/matchers/have_reported_error_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class AnotherTestError < StandardError; end
99
it "warns when used as a value expectation" do
1010
expect {
1111
expect(Rails.error.report(StandardError.new("test error"))).to have_reported_error
12-
}.to raise_error(ArgumentError, "this matcher doesnt work with value expectations")
12+
}.to raise_error(ArgumentError, "this matcher doesn't work with value expectations")
1313
end
1414

1515
context "without constraint" do

0 commit comments

Comments
 (0)