using spec to test a validator
2014-11-28
how to test a custom rails validator using rspec
given rails4 and rspec3, here is a tidy way to test your custom validator:
# spec/validators/domain_name_validator_spec.rb
require 'spec_helper'
class DomainNameValidatable
include ActiveModel::Validations
attr_accessor :domain_name
validates :domain_name, domain_name: true
end
describe DomainNameValidator do
subject { DomainNameValidatable.new }
good = {
'with proper domain name' => ['zeebar.com', 'www.zeebar.com']
}
good.each do |title, good_domain_names|
good_domain_names.each do |good_domain_name|
context "#{title} #{good_domain_name}" do
it 'is valid' do
subject.stubs(domain_name: 'zeebar.com')
expect(subject).to be_valid
end
end
end
end
bad = {
'without domain' => nil,
'with blank domain' => '',
'with mixed case domain' => 'Zeebar.com',
'with short wonky domain' => 'twitter',
'with spacey wonky domain' => 'zeebar.com '
}
bad.each do |title, bad_domain_name|
context "#{title} '#{bad_domain_name}'" do
it 'is invalid' do
subject.stubs(domain_name: bad_domain_name)
expect(subject).to_not be_valid
expect(subject.errors[:domain_name].size).to eq 1
end
end
end
end
remember to add app/validators to your application.config, like to:
config.autoload_paths += %W(#{config.root}/lib #{config.root}/app/validators)
and of course you will need the validator itself:
# app/validators/DomainNameValidator.rb
class DomainNameValidator < ActiveModel::EachValidator
# is not nearly as permissible as it probably should be
DOMAIN_NAME_REGEX = /\A[a-z][a-z0-9]+(\.[a-z][a-z0-9]+)+\z/i
def validate_each(record, attribute, value)
if value
if value.downcase != value
record.errors[attribute] << (options[:message] || "domain names should be lowercase")
else
unless value =~ DOMAIN_NAME_REGEX
record.errors[attribute] << (options[:message] || "does not look like a domain name, example: zeebar.com")
end
end
else
record.errors[attribute] << (options[:message] || "missing value")
end
end
end
note that, since rspecs are ruby, you can Dry your test rig using whatever hash/table structure best suites your case topology.