Skip to content

Commit

Permalink
confirmation: Refactor to use AttributeSetter
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mcmire committed Dec 31, 2015
1 parent 2e93e80 commit 417f289
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 29 deletions.
Expand Up @@ -89,7 +89,7 @@ def initialize(attribute)
end

def simple_description
"validate that #{@confirmation_attribute} matches #{@attribute}"
"validate that :#{@confirmation_attribute} matches :#{@attribute}"
end

def matches?(subject)
Expand All @@ -103,43 +103,43 @@ def matches?(subject)
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,
values: { attribute: attribute }
)
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
Expand Down
10 changes: 3 additions & 7 deletions spec/support/unit/record_validating_confirmation_builder.rb
Expand Up @@ -25,9 +25,8 @@ def message=(message)
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"
Expand All @@ -44,11 +43,8 @@ def attribute_that_receives_error
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
Expand Down
Expand Up @@ -6,7 +6,7 @@
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
Expand All @@ -29,11 +29,65 @@
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

Expand Down

0 comments on commit 417f289

Please sign in to comment.