mirror of
https://github.com/thoughtbot/shoulda-matchers.git
synced 2022-11-09 12:01:38 -05:00
Adds accept_nested_attributes_for matcher
Currently supports the options "allow_destroy", "limit", and "update_only"
This commit is contained in:
parent
6297c73615
commit
ee7422280d
3 changed files with 212 additions and 0 deletions
|
@ -4,6 +4,7 @@ require 'shoulda/matchers/active_record/have_db_index_matcher'
|
|||
require 'shoulda/matchers/active_record/have_readonly_attribute_matcher'
|
||||
require 'shoulda/matchers/active_record/serialize_matcher'
|
||||
require 'shoulda/matchers/active_record/query_the_database_matcher'
|
||||
require 'shoulda/matchers/active_record/accept_nested_attributes_for_matcher'
|
||||
|
||||
module Shoulda
|
||||
module Matchers
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
module Shoulda
|
||||
module Matchers
|
||||
module ActiveRecord
|
||||
# Ensures that the model can accept nested attributes for the specified
|
||||
# association.
|
||||
#
|
||||
# Options:
|
||||
# * <tt>allow_destroy</tt> - Whether or not to allow destroy
|
||||
# * <tt>limit</tt> - Max number of nested attributes
|
||||
# * <tt>update_only</tt> - Only allow updates
|
||||
#
|
||||
# Example:
|
||||
# it { should accept_nested_attributes_for(:friends) }
|
||||
# it { should accept_nested_attributes_for(:friends).
|
||||
# allow_destroy(true).
|
||||
# limit(4) }
|
||||
# it { should accept_nested_attributes_for(:friends).
|
||||
# update_only(true) }
|
||||
#
|
||||
def accept_nested_attributes_for(name)
|
||||
AcceptNestedAttributesForMatcher.new(name)
|
||||
end
|
||||
|
||||
class AcceptNestedAttributesForMatcher
|
||||
def initialize(name)
|
||||
@name = name
|
||||
self
|
||||
end
|
||||
|
||||
def allow_destroy(allow_destroy)
|
||||
@allow_destroy = allow_destroy
|
||||
self
|
||||
end
|
||||
|
||||
def limit(limit)
|
||||
@limit = limit
|
||||
self
|
||||
end
|
||||
|
||||
def update_only(update_only)
|
||||
@update_only = update_only
|
||||
self
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
@subject = subject
|
||||
exists? &&
|
||||
allow_destroy_correct? &&
|
||||
limit_correct? &&
|
||||
update_only_correct?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Expected #{expectation} (#{@problem})"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Did not expect #{expectation}"
|
||||
end
|
||||
|
||||
def description
|
||||
description = "accepts_nested_attributes_for :#{@name}"
|
||||
description += " allow_destroy => #{@allow_destroy}" if @allow_destroy
|
||||
description += " limit => #{@limit}" if @limit
|
||||
description += " update_only => #{@update_only}" if @update_only
|
||||
description
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def exists?
|
||||
if config
|
||||
true
|
||||
else
|
||||
@problem = "is not declared"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def allow_destroy_correct?
|
||||
if @allow_destroy.nil? || @allow_destroy == config[:allow_destroy]
|
||||
true
|
||||
else
|
||||
@problem = (@allow_destroy ? "should" : "should not") +
|
||||
" allow destroy"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def limit_correct?
|
||||
if @limit.nil? || @limit == config[:limit]
|
||||
true
|
||||
else
|
||||
@problem = "limit should be #@limit, got #{config[:limit]}"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def update_only_correct?
|
||||
if @update_only.nil? || @update_only == config[:update_only]
|
||||
true
|
||||
else
|
||||
@problem = (@update_only ? "should" : "should not") +
|
||||
" be update only"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def config
|
||||
model_config[@name]
|
||||
end
|
||||
|
||||
def model_config
|
||||
model_class.nested_attributes_options
|
||||
end
|
||||
|
||||
def model_class
|
||||
@subject.class
|
||||
end
|
||||
|
||||
def expectation
|
||||
"#{model_class.name} to accept nested attributes for #{@name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,84 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Shoulda::Matchers::ActiveRecord::AcceptNestedAttributesForMatcher do
|
||||
before do
|
||||
define_model :child, :parent_id => :integer
|
||||
define_model :parent do
|
||||
has_many :children
|
||||
end
|
||||
end
|
||||
|
||||
let(:parent) { Parent.new }
|
||||
let(:matcher) { accept_nested_attributes_for(:children) }
|
||||
|
||||
it "should accept an existing declaration" do
|
||||
Parent.accepts_nested_attributes_for :children
|
||||
matcher.matches?(parent).should be_true
|
||||
end
|
||||
|
||||
it "should reject a missing declaration" do
|
||||
matcher.matches?(parent).should be_false
|
||||
matcher.failure_message.should == "Expected Parent to accept nested attributes for children (is not declared)"
|
||||
end
|
||||
|
||||
context "allow_destroy" do
|
||||
it "should accept a valid truthy value" do
|
||||
Parent.accepts_nested_attributes_for :children, :allow_destroy => true
|
||||
matcher.allow_destroy(true).matches?(parent).should be_true
|
||||
end
|
||||
|
||||
it "should accept a valid falsey value" do
|
||||
Parent.accepts_nested_attributes_for :children, :allow_destroy => false
|
||||
matcher.allow_destroy(false).matches?(parent).should be_true
|
||||
end
|
||||
|
||||
it "should reject an invalid truthy value" do
|
||||
Parent.accepts_nested_attributes_for :children, :allow_destroy => true
|
||||
matcher.allow_destroy(false).matches?(parent).should be_false
|
||||
matcher.failure_message.should =~ /should not allow destroy/
|
||||
end
|
||||
|
||||
it "should reject an invalid falsey value" do
|
||||
Parent.accepts_nested_attributes_for :children, :allow_destroy => false
|
||||
matcher.allow_destroy(true).matches?(parent).should be_false
|
||||
matcher.failure_message.should =~ /should allow destroy/
|
||||
end
|
||||
end
|
||||
|
||||
context "limit" do
|
||||
it "should accept a correct value" do
|
||||
Parent.accepts_nested_attributes_for :children, :limit => 3
|
||||
matcher.limit(3).matches?(parent).should be_true
|
||||
end
|
||||
|
||||
it "should reject a false value" do
|
||||
Parent.accepts_nested_attributes_for :children, :limit => 3
|
||||
matcher.limit(2).matches?(parent).should be_false
|
||||
matcher.failure_message.should =~ /limit should be 2, got 3/
|
||||
end
|
||||
end
|
||||
|
||||
context "update_only" do
|
||||
it "should accept a valid truthy value" do
|
||||
Parent.accepts_nested_attributes_for :children, :update_only => true
|
||||
matcher.update_only(true).matches?(parent).should be_true
|
||||
end
|
||||
|
||||
it "should accept a valid falsey value" do
|
||||
Parent.accepts_nested_attributes_for :children, :update_only => false
|
||||
matcher.update_only(false).matches?(parent).should be_true
|
||||
end
|
||||
|
||||
it "should reject an invalid truthy value" do
|
||||
Parent.accepts_nested_attributes_for :children, :update_only => true
|
||||
matcher.update_only(false).matches?(parent).should be_false
|
||||
matcher.failure_message.should =~ /should not be update only/
|
||||
end
|
||||
|
||||
it "should reject an invalid falsey value" do
|
||||
Parent.accepts_nested_attributes_for :children, :update_only => false
|
||||
matcher.update_only(true).matches?(parent).should be_false
|
||||
matcher.failure_message.should =~ /should be update only/
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue