confirmation: Refactor to use AttributeSetter

When the confirmation matcher is setting the confirmation attribute, we
want it to raise an exception if the model does not have that attribute,
same as if it would raise an exception if the attribute under test did
not exist.
This commit is contained in:
Elliot Winkler 2015-12-21 14:15:19 -05:00
parent 2e93e80b76
commit 417f289a86
3 changed files with 79 additions and 29 deletions

View File

@ -89,7 +89,7 @@ module Shoulda
end
def simple_description
"validate that #{@confirmation_attribute} matches #{@attribute}"
"validate that :#{@confirmation_attribute} matches :#{@attribute}"
end
def matches?(subject)
@ -103,30 +103,27 @@ module Shoulda
private
def disallows_different_value
set_confirmation('some value')
disallows_value_of('different value') do |matcher|
qualify_matcher(matcher)
qualify_matcher(matcher, 'some value')
end
end
def allows_same_value
set_confirmation('same value')
allows_value_of('same value') do |matcher|
qualify_matcher(matcher)
qualify_matcher(matcher, 'same value')
end
end
def allows_missing_confirmation
set_confirmation(nil)
allows_value_of('any value') do |matcher|
qualify_matcher(matcher)
qualify_matcher(matcher, nil)
end
end
def qualify_matcher(matcher)
def qualify_matcher(matcher, confirmation_attribute_value)
matcher.values_to_preset = {
confirmation_attribute => confirmation_attribute_value
}
matcher.with_message(
@expected_message,
against: confirmation_attribute,
@ -134,12 +131,15 @@ module Shoulda
)
end
def set_confirmation(val)
setter = :"#{@confirmation_attribute}="
def set_confirmation(value)
@last_value_set_on_confirmation_attribute = value
if @subject.respond_to?(setter)
@subject.__send__(setter, val)
end
AttributeSetter.set(
matcher_name: 'confirmation',
object: @subject,
attribute_name: confirmation_attribute,
value: value
)
end
end
end

View File

@ -25,9 +25,8 @@ module UnitTests
end
def attribute_to_confirm
:attribute_to_confirm
options.fetch(:attribute, :attribute_to_confirm)
end
alias_method :attribute, :attribute_to_confirm
def confirmation_attribute
:"#{attribute_to_confirm}_confirmation"
@ -44,11 +43,8 @@ module UnitTests
private
def create_model
_attribute = attribute_to_confirm
_options = options
define_model(model_name, _attribute => :string) do
validates_confirmation_of(_attribute, _options)
define_model(model_name, attribute_to_confirm => :string) do |model|
model.validates_confirmation_of(attribute_to_confirm, options)
end
end
end

View File

@ -6,7 +6,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :m
context '#description' do
it 'states that the confirmation must match its base attribute' do
builder = builder_for_record_validating_confirmation
message = "validate that #{builder.confirmation_attribute} matches #{builder.attribute_to_confirm}"
message = "validate that :#{builder.confirmation_attribute} matches :#{builder.attribute_to_confirm}"
matcher = described_class.new(builder.attribute_to_confirm)
expect(matcher.description).to eq(message)
end
@ -29,11 +29,65 @@ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :m
end
end
context 'when the model does not have a confirmation validation' do
it 'fails' do
model = define_model(:example, attribute_to_confirm: :string)
record = model.new
expect(record).not_to validate_confirmation_of(:attribute_to_confirm)
context 'when the model does not have a confirmation attribute' do
it 'raises an AttributeDoesNotExistError' do
model = define_model(:example)
assertion = lambda do
expect(model.new).to validate_confirmation_of(:attribute_to_confirm)
end
message = <<-MESSAGE.rstrip
The matcher attempted to set :attribute_to_confirm_confirmation to "some
value" on the Example, but that attribute does not exist.
MESSAGE
expect(&assertion).to raise_error(
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeDoesNotExistError,
message
)
end
end
context 'when the model does not have the attribute under test' do
it 'raises an AttributeDoesNotExistError' do
model = define_model(:example, attribute_to_confirm_confirmation: :string)
assertion = lambda do
expect(model.new).to validate_confirmation_of(:attribute_to_confirm)
end
message = <<-MESSAGE.rstrip
The matcher attempted to set :attribute_to_confirm to "different value"
on the Example, but that attribute does not exist.
MESSAGE
expect(&assertion).to raise_error(
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeDoesNotExistError,
message
)
end
end
context 'when the model has all attributes, but does not have the validation' do
it 'fails with an appropriate failure message' do
model = define_model(:example, attribute_to_confirm: :string) do
attr_accessor :attribute_to_confirm_confirmation
end
assertion = lambda do
expect(model.new).to validate_confirmation_of(:attribute_to_confirm)
end
message = <<-MESSAGE
Example did not properly validate that
:attribute_to_confirm_confirmation matches :attribute_to_confirm.
After setting :attribute_to_confirm_confirmation to "some value", then
setting :attribute_to_confirm to "different value", the matcher
expected the Example to be invalid, but it was valid instead.
MESSAGE
expect(&assertion).to fail_with_message(message)
end
end