1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
# frozen_string_literal: true
require "cases/helper"
require "models/topic"
class ValidatesWithTest < ActiveModel::TestCase
def teardown
Topic.clear_validators!
end
ERROR_MESSAGE = "Validation error from validator"
OTHER_ERROR_MESSAGE = "Validation error from other validator"
class ValidatorThatAddsErrors < ActiveModel::Validator
def validate(record)
record.errors[:base] << ERROR_MESSAGE
end
end
class OtherValidatorThatAddsErrors < ActiveModel::Validator
def validate(record)
record.errors[:base] << OTHER_ERROR_MESSAGE
end
end
class ValidatorThatDoesNotAddErrors < ActiveModel::Validator
def validate(record)
end
end
class ValidatorThatValidatesOptions < ActiveModel::Validator
def validate(record)
if options[:field] == :first_name
record.errors[:base] << ERROR_MESSAGE
end
end
end
class ValidatorPerEachAttribute < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << "Value is #{value}"
end
end
class ValidatorCheckValidity < ActiveModel::EachValidator
def check_validity!
raise "boom!"
end
end
test "validation with class that adds errors" do
Topic.validates_with(ValidatorThatAddsErrors)
topic = Topic.new
assert topic.invalid?, "A class that adds errors causes the record to be invalid"
assert_includes topic.errors[:base], ERROR_MESSAGE
end
test "with a class that returns valid" do
Topic.validates_with(ValidatorThatDoesNotAddErrors)
topic = Topic.new
assert topic.valid?, "A class that does not add errors does not cause the record to be invalid"
end
test "with multiple classes" do
Topic.validates_with(ValidatorThatAddsErrors, OtherValidatorThatAddsErrors)
topic = Topic.new
assert_predicate topic, :invalid?
assert_includes topic.errors[:base], ERROR_MESSAGE
assert_includes topic.errors[:base], OTHER_ERROR_MESSAGE
end
test "passes all configuration options to the validator class" do
topic = Topic.new
validator = Minitest::Mock.new
validator.expect(:new, validator, [{ foo: :bar, if: :condition_is_true, class: Topic }])
validator.expect(:validate, nil, [topic])
validator.expect(:is_a?, false, [Symbol])
validator.expect(:is_a?, false, [String])
Topic.validates_with(validator, if: :condition_is_true, foo: :bar)
assert_predicate topic, :valid?
validator.verify
end
test "validates_with with options" do
Topic.validates_with(ValidatorThatValidatesOptions, field: :first_name)
topic = Topic.new
assert_predicate topic, :invalid?
assert_includes topic.errors[:base], ERROR_MESSAGE
end
test "validates_with each validator" do
Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content])
topic = Topic.new title: "Title", content: "Content"
assert_predicate topic, :invalid?
assert_equal ["Value is Title"], topic.errors[:title]
assert_equal ["Value is Content"], topic.errors[:content]
end
test "each validator checks validity" do
assert_raise RuntimeError do
Topic.validates_with(ValidatorCheckValidity, attributes: [:title])
end
end
test "each validator expects attributes to be given" do
assert_raise ArgumentError do
Topic.validates_with(ValidatorPerEachAttribute)
end
end
test "each validator skip nil values if :allow_nil is set to true" do
Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content], allow_nil: true)
topic = Topic.new content: ""
assert_predicate topic, :invalid?
assert_empty topic.errors[:title]
assert_equal ["Value is "], topic.errors[:content]
end
test "each validator skip blank values if :allow_blank is set to true" do
Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content], allow_blank: true)
topic = Topic.new content: ""
assert_predicate topic, :valid?
assert_empty topic.errors[:title]
assert_empty topic.errors[:content]
end
test "validates_with can validate with an instance method" do
Topic.validates :title, with: :my_validation
topic = Topic.new title: "foo"
assert_predicate topic, :valid?
assert_empty topic.errors[:title]
topic = Topic.new
assert_not_predicate topic, :valid?
assert_equal ["is missing"], topic.errors[:title]
end
test "optionally pass in the attribute being validated when validating with an instance method" do
Topic.validates :title, :content, with: :my_validation_with_arg
topic = Topic.new title: "foo"
assert_not_predicate topic, :valid?
assert_empty topic.errors[:title]
assert_equal ["is missing"], topic.errors[:content]
end
end
|