-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
base: main
Are you sure you want to change the base?
Conversation
8b837a8
to
d2d0e51
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
return true if @attributes.empty? | ||
return false if @error_subscriber.events.empty? | ||
|
||
event_context = @error_subscriber.events.last[1].with_indifferent_access["context"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it lock and match only on the last one reported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pirj yeah, it does. I've been debating this, but this works in our case just fine.
But questions keep popping in my head. Should we look through array of errors? what to do if there will be more than 1? Should we match amount of errors too?
I don't have good answers for these. So this is my dumbest approach -- checking last error only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should match like we do with scheduled jobs, if there is a matching one among reported, it matches.
I don’t see a reason to add count matches now. This can be added later.
b38ff1c
to
87ebd2a
Compare
71685ad
to
6135d5d
Compare
Scenario: Using in controller specs | ||
Given a file named "spec/controllers/users_controller_spec.rb" with: | ||
"""ruby | ||
require "rails_helper" | ||
|
||
RSpec.describe UsersController, type: :controller do | ||
describe "POST #create" do | ||
it "reports validation errors" do | ||
expect { | ||
post :create, params: { user: { email: "invalid" } } | ||
}.to have_reported_error(ValidationError) | ||
end | ||
end | ||
end | ||
""" | ||
When I run `rspec spec/controllers/users_controller_spec.rb` | ||
Then the examples should all pass | ||
|
||
Scenario: Using in request specs | ||
Given a file named "spec/requests/users_spec.rb" with: | ||
"""ruby | ||
require "rails_helper" | ||
|
||
RSpec.describe "Users", type: :request do | ||
describe "POST /users" do | ||
it "reports processing errors" do | ||
expect { | ||
post "/users", params: { user: { name: "Test" } } | ||
}.to have_reported_error.with(context: "user_creation") | ||
end | ||
end | ||
end | ||
""" | ||
When I run `rspec spec/requests/users_spec.rb` | ||
Then the examples should all pass | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a controller / request specific matcher so these feel out of place, why these, why not every aspect of Rails... I'd just cut them.
👋 I think this would be a great addition, sorry for the size of the review its been on my todo list for a while, its mostly just grammar / wording tweaks plus a few "fit" things. The one change I do want to see though is dropping instance matching, I don't think it makes sense over just providing class / message / using with. |
Commit grammar improvements Co-authored-by: Jon Rowe <mail@jonrowe.co.uk>
@JonRowe thanks for review.
Which of these you would rather go with? or
?? I assume, that first option is prefered to keep similarity with |
Given that you already have
But if you insisted on |
It makes sense to separate matching of args passed to |
The only argument that the exception class accepts is "message". We can of course subclass it and support way more than that, but I'm not sure if we should support this in a matcher? I have a feeling, that having a matcher interface similar to |
I hadn't clocked that the extra attributes were in addition to the error, I think matching the |
Here is a source code for Rails.error.report. These attributes in rails case have a name "context". so |
c1134da
to
f90fc3b
Compare
f90fc3b
to
2488a71
Compare
# @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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such a constant is already defined in the basematcher, do we need another one?
@actual_error = nil | ||
@attributes = {} | ||
@error_subscriber = nil | ||
|
||
case expected_error_or_message | ||
when nil | ||
when nil, UndefinedValue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually make a distinction between those two, where nil is typically a sign of a mistake. For some matchers, we warn if nil is passed. Do you think there can be legitimate cases of passing nil as an argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, similar to error_raised you can just expect an error to be raise, but don't care which one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is raise_error()
is to expect any exception, no matter which; but raise_error(nil)
is usually an indication of a mistake in the spec itself. See rspec/rspec-expectations#1142
This warning may explain it better.
Similarly, expect { report… }.to have_reported_error()
should pass when any kind of error has been reported, while passing a nil as the first argument should emit a warning.
fixes #2827
rspec-rails is missing support for Rails ErrorReporter, this was introduced to rails in v7 and has been evolving ever since. With my client, we have moved to using ErrorReporter as a unified error reporting interface, so we can easily move from one error tracking software to another with minimal code changes. And we had a need to test this interface with rspec, so we implemented our own matcher to handle this.
I'm suggesting our internal implementation as is. This is probably not suitable as is for this gem, but I'd like to open discussion with this starting point.
Example usage