Skip to content
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

'RSpec/PredicateMatcher' explicit style conflicts with Rails 'have_http_status' matcher #806

Closed
yorkxin opened this issue Aug 14, 2019 · 8 comments

Comments

@yorkxin
Copy link

yorkxin commented Aug 14, 2019

Background

Our engineering team prefer expect(object.good?).to be(true) over expect(object).to be_good so that it's easier to search for "good?" method name across the whole code base.

Therefore, we are using the following settings for RSpec/PredicateMatcher:

RSpec/PredicateMatcher:
  Strict: true
  EnforcedStyle: explicit

However, this cop also finds the rspec-rails have_http_status matcher should be changed:

Instead of:

expect(response).to have_http_status(:success)

The cop would suggest:

expect(response.has_http_status?(:success)).to be(true)

Which results in method not found of Response#has_http_status?.

Questions

Is this the expected behavior? If so, what settings should I use to allow have_http_status?

Current Workaround

Our current workaround is to use a dirty hack to add have_http_status to built-in matchers list?:

# .rubocoprc.rb
RuboCop::Cop::RSpec::ExplicitHelper::BUILT_IN_MATCHERS =
  RuboCop::Cop::RSpec::ExplicitHelper::BUILT_IN_MATCHERS.dup.push('have_http_status').freeze
# .rubocop.yml 
require: 
- ./rubocoprc.rb
@pirj
Copy link
Member

pirj commented Aug 14, 2019

@chitsaou I believe have_http_status clashes with predicate matchers, and technically auto-correction is correct.

I don't see a reason not to include have_http_status to BUILT_IN_MATCHERS by default.
However, it's a special case, different from the other built-in matchers. Ignoring this offence might not be the best choice, as it's still possible to correct the example:

- expect(response).to have_http_status(:success)
+ expect(response.status).to be(:success)

Which approach would you prefer?

@dgollahon dgollahon mentioned this issue Aug 15, 2019
5 tasks
@dgollahon
Copy link
Contributor

dgollahon commented Aug 15, 2019

We should double check for more common have_ matchers in rspec-rails or other common matching tools and make sure we haven't overlooked any others.

It might possibly make sense to add a user-customizable ignore list as well for custom matchers.

Also, I added a note to #721 that we should mark this cop as unsafe.

@pirj
Copy link
Member

pirj commented Aug 17, 2019

shoulda-matchers:

Also those:

have_secure_password corresponds to has_secure_password
have_and_belong_to_many tests your has_and_belongs_to_many associations.
have_db_column tests that the table that backs your model has a specific column.
have_db_index tests that the table that backs your model has an index on a specific column.
have_many tests your has_many associations.
have_one tests your has_one associations.
have_readonly_attribute tests usage of the attr_readonly macro.

rspec-rails:

  • have_http_status
  • have_rendered
  • have_enqueued_mail - block matcher

I don't see any common pattern here, probably they should all be excluded.

@yorkxin
Copy link
Author

yorkxin commented Aug 18, 2019

Thanks for all of your replies. It's true that there might be other have_* matchers from libraries, such as these from webmock:

have_been_made
have_been_requested
have_not_been_made
have_requested(method, uri)
have_not_requested(method, uri)

Wouldn't it be great if we can configure ignore list for this cop?

@pirj
Copy link
Member

pirj commented Nov 25, 2019

@chitsaou #838 has just been released in 1.37.0 allowing you to configure RSpec/PredicateMatcher to ignore specific matchers:

RSpec/PredicateMatcher:
  AllowedExplicitMatchers:
    - have_http_status
    - have_been_made

Do you think this is sufficient?

On a side note, it would be incredible to add such configuration to corresponding projects (e.g. webmock and shoulda-matchers), however, I'm afraid it will override each other.
@Darhazer do you think it's a reasonable approach to avoid pulling the list of such third-party matchers into default rubocop-rspec configuration? Is it possible with the current RuboCop's configuration system?

@Darhazer
Copy link
Member

I don't think it's currently possible.
It would be nice to provide such an API for 3rd party extensions to adjust rubocop config, although it could become rather complicated.

For the time being, we will need to pull the list of matchers from popular gems.

@yorkxin
Copy link
Author

yorkxin commented Nov 26, 2019

@pirj This new option of RSpec/PredicateMatcher cop allows us to adjust the whitelist. Really appreciate your help and the works from @mkrawc. You're awesome 🎉

I agree that managing a list might be hard, but at least we have a start :)

Thank you all again!

@yorkxin yorkxin closed this as completed Nov 26, 2019
@pirj
Copy link
Member

pirj commented Jun 9, 2020

reasonable approach to avoid pulling the list of such third-party matchers into default rubocop-rspec configuration

Stumbled across inherit_mode:

However, advanced users can still merge arrays using the inherit_mode setting.

If you guys are interested, we may add something like:

inherit_mode:
  merge:
    - RSpec/PredicateMatcher/AllowedExplicitMatchers

add your settings to a third-party gem and see if it's being pulled.

Would you like to hack on it @chitsaou ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants