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.
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 send
ing 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.