RSpec how is be_invalid matcher made available

67 views Asked by At

I noticed following line

expect(actual).to be_invalid

while I was looking at https://github.com/perfectline/validates_url/blob/81ec1516423af0b4fdc7cabbcda0089e434f2703/lib/validate_url/rspec_matcher.rb#L5

I tried to look for that matcher's implementation in rspec-core, rspec-expectations and rspec-rails gems but I could find only be_valid and that too only in rspec-rails https://rubydoc.info/gems/rspec-rails/RSpec%2FRails%2FMatchers:be_valid

which made me wonder how does be_invalid is made available because when I used that matcher in a test example it didn't raised any not defined method error.

Can anybody please help in making me understand how does that work?

Thanks.

1

There are 1 answers

0
aridlehoover On BEST ANSWER

A method that ends in a question mark is called a predicate. They look like this:

[].empty?

RSpec has a pretty cool predicate matcher that looks like this:

expect([]).to be_empty

It works by using method missing to select the BePredicate matcher. The matcher works by stripping off the be_ with a regex and appending a ?, then sending that method to the subject of the expectation.

be_valid and be_invalid are no different. Both valid? and invalid? are defined on ActiveModel::Validations.

So, if you're doing this:

expect(User.new).to be_invalid

RSpec is using its predicate matcher to call User.new.invalid? and return the result. Same goes for be_valid. Unless, that is, you're using RSpec::Rails, which contains a BeValid matcher that overrides RSpec's predicate matcher so that it can print out all the validation errors when the spec fails.