RspecModelValidations
Extra matchers to improve testing of model validation
Testing model validation can be a bit clunky:
-
model.valid?
test the entire model so it can lead to errors - specific error on attribute can be test with
model.added?
orerrors[:attribute]
but options or message must be provided - attribute setting and validation trigger must be call
- as validation are test through "raw code" failure message can be hard to understand
rspec_model_validations
make testing smoother by adding matchers to focus test on specific attribute / validation.
# model
validates :attribute, numericality: true
# spec
expect(model).to invalidate(:attribute).with(:blank, :not_a_number).on nil
# equivalent to
model.attribute = nil
model.validate
expect(model.errors).to be_added :attribute, :blank
expect(model.errors).to be_added :attribute, :not_a_number, value: nil
Requirements
- ~> 1.0: rails ~> 7.0
Note: it should be able to run with older version of rails but behaviour is not garanted.
Installation
- Add this gem to your application in :test env
gem 'rspec_model_validations', '~> 1.0', require: false, group: :test
- Setup spec/rails_helper.rb file to access matchers
# Add additional requires below this line. Rails is not loaded until this point!
require 'rspec_model_validations'
# ...
RSpec.configure do |config|
config.include RspecModelValidations::Matchers
end
Usage
Test validation errors
invalidate :attribute
test errors on a specific attribute.
It run validation and test that the targeted attribute have at least one error.
model.attribute = nil
expect(model).to invalidate :attribute
# equivalent to
model.attribute = nil
model.validate
expect(model.errors[:attribute]).to be_present
Options:
-
with
specify which errors type must be present. It accept single or multiple symbols.
model.attribute = nil
expect(model).to invalidate(:attribute).with :blank, :not_a_number
# equivalent to
model.attribute = nil
model.validate
expect(model.errors.group_by_attribute(:attribute).map(&:type)).to include(:blank, :not_a_number)
-
on
set the attribute value
expect(model).to invalidate(:attribute).on nil
# equivalent to
model.attribute = nil
model.validate
expect(model.errors[:attribute]).to be_present
Test successfull validation
validate :attribute
test a specific attribute validity.
It run validation and then test that none errors are related to the given attribute.
model.attribute = 9
expect(model).to validate :attribute
# equivalent to
model.attribute = 9
model.validate
expect(model.errors[:attribute]).to be_empty
Options:
-
on
see invalidate on option