Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9294186
first pass at have_reported_error matcher
skatkov Jun 4, 2025
231ec91
Adding a feature
skatkov Jun 7, 2025
040ea69
simplify matcher/readmer.md
skatkov Jun 14, 2025
584a93b
Remove mocks out of tests
skatkov Jun 14, 2025
0c2ce03
test failure messages better
skatkov Jun 14, 2025
404f6bb
rewrite specs
skatkov Jun 20, 2025
d32437f
should require a block matcher
skatkov Jun 22, 2025
9e938ce
Create ErrorEvent struct to store errors
skatkov Jun 22, 2025
bc9acfb
simplify matcher
skatkov Jun 22, 2025
f41ba1f
disable matcher chaining
skatkov Jun 22, 2025
7de1c60
improved argument error message in case block is not passed to matcher
skatkov Jun 22, 2025
32d35ef
further clean-up
skatkov Jun 22, 2025
492c728
Apply suggestions from code review
skatkov Jun 25, 2025
c3e9343
clean-up features
skatkov Jun 27, 2025
9907d1b
remove a require from test
skatkov Jul 1, 2025
f58e4a7
rename .with to .with_context
skatkov Jul 1, 2025
834b3bc
have_reported_error to accept class name and a message
skatkov Jul 1, 2025
dad179b
switch to error_report matcher type of api
skatkov Jul 1, 2025
1b81eac
refactor
skatkov Jul 1, 2025
a30c7ae
Using UndefinedValue as a default attribute
skatkov Jul 1, 2025
07a63d8
Look through all errors, don't just go with last error
skatkov Jul 1, 2025
9d87a40
warn about nil being passed
skatkov Jul 9, 2025
d620e9d
Use ErrorCollector from Rails instead of self-written version'
Aug 4, 2025
07a8868
Use defined UNDEFINED value instead of defining our own
Aug 4, 2025
ef38475
Update features/matchers/README.md
pirj Aug 8, 2025
248e743
Define supports_value_expectations? to false
Aug 30, 2025
cf1def7
remove log/development.log
Aug 30, 2025
569fa0e
Don't use default values in HaveReportedError initializer
Aug 30, 2025
c09b42c
Don't allow to redefine attributes with chaining in with_context method
Aug 30, 2025
47840d1
adjust .feature file to properly illustrate report usage
Aug 30, 2025
b6d0b0d
handle hegated matchers safely, not allowing any attributes
Aug 31, 2025
091d8b8
Remove from features/matchers/README.md
skatkov Aug 31, 2025
ad78776
cleaning up a class
Sep 1, 2025
aa4c84d
remove context attribute in specs
Sep 1, 2025
b20a699
block chaining for .or method as well
Sep 24, 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
7 changes: 7 additions & 0 deletions features/matchers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,10 @@ expect(response).to render_template(template_name)
# and it is not persisted
expect(assigns(:widget)).to be_a_new(Widget)
```

### error reporting

```ruby
# passes when any error is reported
expect { Rails.error.report(StandardError.new) }.to have_reported_error
```
199 changes: 199 additions & 0 deletions features/matchers/have_reported_error_matcher.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
Feature: `have_reported_error` matcher

The `have_reported_error` matcher is used to check if an error was reported
to Rails error reporting system (`Rails.error`). It can match against error
classes, messages, and attributes.

The matcher supports several matching strategies:
* Any error reported
* A specific error class
* A specific error class with message
* Error message patterns using regular expressions
* Message-only matching (any class)
* Error attributes using `.with_context()`

The matcher is available in all spec types where Rails error reporting is used.

Background:
Given a file named "app/models/user.rb" with:
"""ruby
class User < ApplicationRecord
class ValidationError < StandardError; end
def self.process_data
Rails.error.report(StandardError.new("Processing failed"))
end

def self.process_with_context
Rails.error.report(ArgumentError.new("Invalid input"), severity: :error, context: { topic: "user_processing" })
end

def self.process_custom_error
Rails.error.report(ValidationError.new("Email is invalid"))
end
end
"""

Scenario: Checking for any error being reported
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports errors" do
expect {
User.process_data
}.to have_reported_error
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Checking for message-only matching
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports error with exact message (any class)" do
expect {
User.process_data
}.to have_reported_error("Processing failed")
end

it "reports error with message pattern (any class)" do
expect {
User.process_custom_error
}.to have_reported_error(/Email/)
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Checking for a specific error class
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports a StandardError" do
expect {
User.process_data
}.to have_reported_error(StandardError)
end

it "reports an ArgumentError" do
expect {
User.process_with_context
}.to have_reported_error(ArgumentError)
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Checking for specific error class with message
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports error with specific message" do
expect {
User.process_data
}.to have_reported_error(StandardError, "Processing failed")
end

it "reports ArgumentError with specific message" do
expect {
User.process_with_context
}.to have_reported_error(ArgumentError, "Invalid input")
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Checking error messages using regular expressions
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports errors with a message matching a pattern (any class)" do
expect {
User.process_data
}.to have_reported_error(/Processing/)
end

it "reports specific class with message matching a pattern" do
expect {
User.process_data
}.to have_reported_error(StandardError, /Processing/)
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Constraining error matches to their attributes using `with_context`
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports error with specific context" do
expect {
User.process_with_context
}.to have_reported_error.with_context(context: "user_processing")
end

it "reports error with multiple attributes" do
expect {
User.process_with_context
}.to have_reported_error(ArgumentError).with_context(context: "user_processing", severity: :error)
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Checking custom error classes
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "reports a ValidationError" do
expect {
User.process_custom_error
}.to have_reported_error(User::ValidationError)
end

it "reports ValidationError with specific message" do
expect {
User.process_custom_error
}.to have_reported_error(User::ValidationError, "Email is invalid")
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass

Scenario: Using negation - expecting no errors
Given a file named "spec/models/user_spec.rb" with:
"""ruby
require "rails_helper"

RSpec.describe User do
it "does not report any errors for safe operations" do
expect {
# Safe operation that doesn't report errors
"safe code"
}.not_to have_reported_error
end
end
"""
When I run `rspec spec/models/user_spec.rb`
Then the examples should all pass
1 change: 1 addition & 0 deletions lib/rspec/rails/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module Matchers
require 'rspec/rails/matchers/relation_match_array'
require 'rspec/rails/matchers/be_valid'
require 'rspec/rails/matchers/have_http_status'
require 'rspec/rails/matchers/have_reported_error'
require 'rspec/rails/matchers/send_email'

if RSpec::Rails::FeatureCheck.has_active_job?
Expand Down
Loading
Loading