211 changes: 40 additions & 171 deletions spec/draper/decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
let(:non_active_model_source){ NonActiveModelProduct.new }

describe "#initialize" do
it "sets the model class for the decorator" do
ProductDecorator.new(source).model_class.should == Product
end

it "does not re-apply on instances of itself" do
product_decorator = ProductDecorator.new(source)
ProductDecorator.new(product_decorator).model.should be_instance_of Product
Expand Down Expand Up @@ -168,20 +164,6 @@
end
end

describe "proxying class methods" do
it "pass missing class method calls on to the wrapped class" do
subject.class.sample_class_method.should == "sample class method"
end

it "respond_to a wrapped class method" do
subject.class.should respond_to(:sample_class_method)
end

it "still respond_to its own class methods" do
subject.class.should respond_to(:own_class_method)
end
end

describe "#helpers" do
it "returns a HelperProxy" do
subject.helpers.should be_a Draper::HelperProxy
Expand Down Expand Up @@ -221,75 +203,6 @@
end
end

context(".decorates") do
it "handle plural-like words properly'" do
class Business; end
expect do
class BusinessDecorator < Draper::Decorator
decorates:business
end
BusinessDecorator.model_class.should == Business
end.to_not raise_error
end

context("accepts ActiveRecord like :class_name option too") do
it "accepts constants for :class" do
expect do
class CustomDecorator < Draper::Decorator
decorates :product, :class => Product
end
CustomDecorator.model_class.should == Product
end.to_not raise_error
end

it "accepts constants for :class_name" do
expect do
class CustomDecorator < Draper::Decorator
decorates :product, :class_name => Product
end
CustomDecorator.model_class.should == Product
end.to_not raise_error
end

it "accepts strings for :class" do
expect do
class CustomDecorator < Draper::Decorator
decorates :product, :class => 'Product'
end
CustomDecorator.model_class.should == Product
end.to_not raise_error
end

it "accepts strings for :class_name" do
expect do
class CustomDecorator < Draper::Decorator
decorates :product, :class_name => 'Product'
end
CustomDecorator.model_class.should == Product
end.to_not raise_error
end
end

it "creates a named accessor for the wrapped model" do
pd = ProductDecorator.new(source)
pd.send(:product).should == source
end

context("namespaced model supporting") do
let(:source){ Namespace::Product.new }

it "sets the model class for the decorator" do
decorator = Namespace::ProductDecorator.new(source)
decorator.model_class.should == Namespace::Product
end

it "creates a named accessor for the wrapped model" do
pd = Namespace::ProductDecorator.new(source)
pd.send(:product).should == source
end
end
end

describe ".decorates_association" do
context "for ActiveModel collection associations" do
before { subject.class.decorates_association :similar_products }
Expand Down Expand Up @@ -515,72 +428,6 @@ class CustomDecorator < Draper::Decorator
subject.block{"marker"}.should == "marker"
end

context ".find" do
it "lookup the associated model when passed an integer" do
pd = ProductDecorator.find(1)
pd.should be_instance_of(ProductDecorator)
pd.model.should be_instance_of(Product)
end

it "lookup the associated model when passed a string" do
pd = ProductDecorator.find("1")
pd.should be_instance_of(ProductDecorator)
pd.model.should be_instance_of(Product)
end

it "accept and store a context" do
pd = ProductDecorator.find(1, :context => :admin)
pd.context.should == :admin
end
end

context ".find_by_(x)" do
it "runs the similarly named finder" do
Product.should_receive(:find_by_name)
ProductDecorator.find_by_name("apples")
end

it "returns a decorated result" do
ProductDecorator.find_by_name("apples").should be_kind_of(ProductDecorator)
end

it "runs complex finders" do
Product.should_receive(:find_by_name_and_size)
ProductDecorator.find_by_name_and_size("apples", "large")
end

it "runs find_all_by_(x) finders" do
Product.should_receive(:find_all_by_name_and_size)
ProductDecorator.find_all_by_name_and_size("apples", "large")
end

it "runs find_last_by_(x) finders" do
Product.should_receive(:find_last_by_name_and_size)
ProductDecorator.find_last_by_name_and_size("apples", "large")
end

it "runs find_or_initialize_by_(x) finders" do
Product.should_receive(:find_or_initialize_by_name_and_size)
ProductDecorator.find_or_initialize_by_name_and_size("apples", "large")
end

it "runs find_or_create_by_(x) finders" do
Product.should_receive(:find_or_create_by_name_and_size)
ProductDecorator.find_or_create_by_name_and_size("apples", "large")
end

it "accepts an options hash" do
Product.should_receive(:find_by_name_and_size).with("apples", "large", {:role => :admin})
ProductDecorator.find_by_name_and_size("apples", "large", {:role => :admin})
end

it "uses the options hash in the decorator instantiation" do
Product.should_receive(:find_by_name_and_size).with("apples", "large", {:role => :admin})
pd = ProductDecorator.find_by_name_and_size("apples", "large", {:role => :admin})
pd.context[:role].should == :admin
end
end

describe "#==" do
it "compares the decorated models" do
other = Draper::Decorator.new(source)
Expand All @@ -599,24 +446,6 @@ class CustomDecorator < Draper::Decorator
end
end

context 'position accessors' do
[:first, :last].each do |method|
context "##{method}" do
it "return a decorated instance" do
ProductDecorator.send(method).should be_instance_of ProductDecorator
end

it "return the #{method} instance of the wrapped class" do
ProductDecorator.send(method).model.should == Product.send(method)
end

it "accept an optional context" do
ProductDecorator.send(method, :context => :admin).context.should == :admin
end
end
end
end

describe "method security" do
subject(:decorator_class) { Draper::Decorator }
let(:security) { stub }
Expand Down Expand Up @@ -720,4 +549,44 @@ class CustomDecorator < Draper::Decorator
subject.kind_of?(subject.class).should be_true
subject.is_a?(subject.class).should be_true
end

describe ".add_finders" do
it "extends the Finders module" do
ProductDecorator.should be_a_kind_of Draper::Finders
end

context "with no options" do
it "infers the finder class" do
ProductDecorator.finder_class.should be Product
end

context "for a namespaced model" do
it "infers the finder class" do
Namespace::ProductDecorator.finder_class.should be Namespace::Product
end
end
end

context "with for: symbol" do
it "sets the finder class" do
FinderDecorator.add_finders for: :product
FinderDecorator.finder_class.should be Product
end
end

context "with for: string" do
it "sets the finder class" do
FinderDecorator.add_finders for: "some_thing"
FinderDecorator.finder_class.should be SomeThing
end
end

context "with for: class" do
it "sets the finder_class" do
FinderDecorator.add_finders for: Namespace::Product
FinderDecorator.finder_class.should be Namespace::Product
end
end
end

end
151 changes: 151 additions & 0 deletions spec/draper/finders_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
require 'spec_helper'

describe Draper::Finders do
describe ".find" do
it "proxies to the model class" do
Product.should_receive(:find).with(1)
ProductDecorator.find(1)
end

it "decorates the result" do
found = Product.new
Product.stub(:find).and_return(found)
decorator = ProductDecorator.find(1)
decorator.should be_a ProductDecorator
decorator.source.should be found
end

it "accepts a context" do
decorator = ProductDecorator.find(1, context: :admin)
decorator.context.should == :admin
end
end

describe ".find_by_(x)" do
it "proxies to the model class" do
Product.should_receive(:find_by_name).with("apples")
ProductDecorator.find_by_name("apples")
end

it "decorates the result" do
found = Product.new
Product.stub(:find_by_name).and_return(found)
decorator = ProductDecorator.find_by_name("apples")
decorator.should be_a ProductDecorator
decorator.source.should be found
end

it "proxies complex finders" do
Product.should_receive(:find_by_name_and_size).with("apples", "large")
ProductDecorator.find_by_name_and_size("apples", "large")
end

it "proxies find_all_by_(x) finders" do
Product.should_receive(:find_all_by_name_and_size).with("apples", "large")
ProductDecorator.find_all_by_name_and_size("apples", "large")
end

it "proxies find_last_by_(x) finders" do
Product.should_receive(:find_last_by_name_and_size).with("apples", "large")
ProductDecorator.find_last_by_name_and_size("apples", "large")
end

it "proxies find_or_initialize_by_(x) finders" do
Product.should_receive(:find_or_initialize_by_name_and_size).with("apples", "large")
ProductDecorator.find_or_initialize_by_name_and_size("apples", "large")
end

it "proxies find_or_create_by_(x) finders" do
Product.should_receive(:find_or_create_by_name_and_size).with("apples", "large")
ProductDecorator.find_or_create_by_name_and_size("apples", "large")
end

it "accepts options" do
Product.should_receive(:find_by_name_and_size).with("apples", "large", {role: :admin})
ProductDecorator.find_by_name_and_size("apples", "large", role: :admin)
end

it "sets the context to the options" do
Product.should_receive(:find_by_name_and_size).with("apples", "large", {role: :admin})
decorator = ProductDecorator.find_by_name_and_size("apples", "large", role: :admin)
decorator.context.should == {role: :admin}
end
end

describe ".all" do
it "returns a decorated collection" do
collection = ProductDecorator.all
collection.should be_a Draper::CollectionDecorator
collection.first.should be_a ProductDecorator
end

it "accepts a context" do
collection = ProductDecorator.all(context: :admin)
collection.first.context.should == :admin
end
end

describe ".first" do
it "proxies to the model class" do
Product.should_receive(:first)
ProductDecorator.first
end

it "decorates the result" do
first = Product.new
Product.stub(:first).and_return(first)
decorator = ProductDecorator.first
decorator.should be_a ProductDecorator
decorator.source.should be first
end

it "accepts a context" do
decorator = ProductDecorator.first(context: :admin)
decorator.context.should == :admin
end
end

describe ".last" do
it "proxies to the model class" do
Product.should_receive(:last)
ProductDecorator.last
end

it "decorates the result" do
last = Product.new
Product.stub(:last).and_return(last)
decorator = ProductDecorator.last
decorator.should be_a ProductDecorator
decorator.source.should be last
end

it "accepts a context" do
decorator = ProductDecorator.last(context: :admin)
decorator.context.should == :admin
end
end

describe "scopes" do
it "proxies to the model class" do
Product.should_receive(:where).with({name: "apples"})
ProductDecorator.where(name: "apples")
end

it "doesn't decorate the result" do
found = [Product.new]
Product.stub(:where).and_return(found)
ProductDecorator.where(name: "apples").should be found
end
end

describe ".respond_to?" do
it "responds to the model's class methods" do
ProductDecorator.should respond_to :sample_class_method
end

it "responds to its own methods" do
ProductDecorator.should respond_to :my_class_method
end
end

end
2 changes: 1 addition & 1 deletion spec/dummy/app/controllers/posts_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class PostsController < ApplicationController
def show
@post = PostDecorator.find(params[:id])
@post = Post.find(params[:id]).decorate
end
end
2 changes: 0 additions & 2 deletions spec/dummy/app/decorators/post_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
class PostDecorator < Draper::Decorator
decorates :post

def posted_date
if created_at.to_date == Date.today
"Today"
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
require './spec/support/samples/decorator_with_denies_all'
require './spec/support/samples/decorator_with_special_methods'
require './spec/support/samples/enumerable_proxy'
require './spec/support/samples/finder_decorator'
require './spec/support/samples/namespaced_product'
require './spec/support/samples/namespaced_product_decorator'
require './spec/support/samples/non_active_model_product'
Expand Down
2 changes: 2 additions & 0 deletions spec/support/samples/finder_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class FinderDecorator < Draper::Decorator
end
2 changes: 1 addition & 1 deletion spec/support/samples/namespaced_product_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module Namespace
class ProductDecorator < Draper::Decorator
decorates :product, :class => Namespace::Product
add_finders
end
end
5 changes: 4 additions & 1 deletion spec/support/samples/product_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
class ProductDecorator < Draper::Decorator
decorates :product
add_finders

def awesome_title
"Awesome Title"
end

def self.my_class_method
end
end
1 change: 0 additions & 1 deletion spec/support/samples/some_thing_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
class SomeThingDecorator < Draper::Decorator
decorates :some_thing
end