Revamp specs

* Use the new `expect().to` syntax
* Avoid general fixtures by minimizing usage of `let` and `subject`
* Define as few support classes as possible, and use them for name
  lookup only - all behavior is introduced by stubbing
This commit is contained in:
Andrew Haines 2013-01-17 02:36:56 +00:00
parent fa2d5274a6
commit 2bfa25a5ad
33 changed files with 1289 additions and 1548 deletions

View File

@ -1,286 +1,259 @@
require 'spec_helper'
require 'support/shared_examples/view_helpers'
describe Draper::CollectionDecorator do
before { ApplicationController.new.view_context }
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator) }
let(:source){ [Product.new, Product.new] }
let(:non_active_model_source){ NonActiveModelProduct.new }
module Draper
describe CollectionDecorator do
it_behaves_like "view helpers", CollectionDecorator.new([])
it "decorates a collection's items" do
subject.each do |item|
item.should be_decorated_with ProductDecorator
end
end
describe "#initialize" do
describe "options validation" do
it "sets the decorated items' source models" do
subject.map{|item| item.source}.should == source
end
it "does not raise error on valid options" do
valid_options = {with: Decorator, context: {}}
expect{CollectionDecorator.new([], valid_options)}.not_to raise_error
end
context "with context" do
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator, context: {some: 'context'}) }
its(:context) { should == {some: 'context'} }
it "passes context to the individual decorators" do
subject.each do |item|
item.context.should == {some: 'context'}
it "raises error on invalid options" do
expect{CollectionDecorator.new([], foo: "bar")}.to raise_error ArgumentError, /Unknown key/
end
end
end
it "does not tie the individual decorators' contexts together" do
subject.each do |item|
item.context.should == {some: 'context'}
item.context = {alt: 'context'}
item.context.should == {alt: 'context'}
context "with context" do
it "stores the context itself" do
context = {some: "context"}
decorator = CollectionDecorator.new([], context: context)
expect(decorator.context).to be context
end
it "passes context to the individual decorators" do
context = {some: "context"}
decorator = CollectionDecorator.new([Product.new, Product.new], context: context)
decorator.each do |item|
expect(item.context).to be context
end
end
end
describe "#context=" do
it "updates the collection decorator's context" do
subject.context = {other: 'context'}
subject.context.should == {other: 'context'}
it "updates the stored context" do
decorator = CollectionDecorator.new([], context: {some: "context"})
new_context = {other: "context"}
decorator.context = new_context
expect(decorator.context).to be new_context
end
context "when the collection is already decorated" do
it "updates the items' context" do
subject.decorated_collection
subject.context = {other: 'context'}
subject.each do |item|
item.context.should == {other: 'context'}
decorator = CollectionDecorator.new([Product.new, Product.new], context: {some: "context"})
decorator.decorated_collection # trigger decoration
new_context = {other: "context"}
decorator.context = new_context
decorator.each do |item|
expect(item.context).to be new_context
end
end
end
context "when the collection has not yet been decorated" do
it "does not trigger decoration" do
subject.should_not_receive(:decorated_collection)
subject.context = {other: 'context'}
decorator = CollectionDecorator.new([])
decorator.should_not_receive(:decorated_collection)
decorator.context = {other: "context"}
end
it "sets context after decoration is triggered" do
subject.context = {other: 'context'}
subject.each do |item|
item.context.should == {other: 'context'}
decorator = CollectionDecorator.new([Product.new, Product.new], context: {some: "context"})
new_context = {other: "context"}
decorator.context = new_context
decorator.each do |item|
expect(item.context).to be new_context
end
end
end
end
end
describe "#initialize" do
describe "options validation" do
let(:valid_options) { {with: ProductDecorator, context: {}} }
describe "item decoration" do
it "sets decorated items' source models" do
collection = [Product.new, Product.new]
decorator = CollectionDecorator.new(collection)
it "does not raise error on valid options" do
expect { Draper::CollectionDecorator.new(source, valid_options) }.to_not raise_error
end
it "raises error on invalid options" do
expect { Draper::CollectionDecorator.new(source, valid_options.merge(foo: 'bar')) }.to raise_error(ArgumentError, /Unknown key/)
end
end
end
describe "item decoration" do
subject { subject_class.new(source, options) }
let(:decorator_classes) { subject.decorated_collection.map(&:class) }
let(:source) { [Product.new, Widget.new] }
context "when the :with option was given" do
let(:options) { {with: SpecificProductDecorator} }
context "and the decorator can't be inferred from the class" do
let(:subject_class) { Draper::CollectionDecorator }
it "uses the :with option" do
decorator_classes.should == [SpecificProductDecorator, SpecificProductDecorator]
decorator.zip collection do |item, source|
expect(item.source).to be source
end
end
context "and the decorator is inferrable from the class" do
let(:subject_class) { ProductsDecorator }
context "when the item decorator is inferrable from the collection decorator" do
context "when the :with option was given" do
it "uses the :with option" do
decorator = ProductsDecorator.new([Product.new], with: OtherDecorator)
it "uses the :with option" do
decorator_classes.should == [SpecificProductDecorator, SpecificProductDecorator]
expect(*decorator).to be_decorated_with OtherDecorator
end
end
context "when the :with option was not given" do
it "infers the item decorator from the collection decorator" do
decorator = ProductsDecorator.new([Product.new])
expect(*decorator).to be_decorated_with ProductDecorator
end
end
end
context "when the item decorator is not inferrable from the collection decorator" do
context "when the :with option was given" do
it "uses the :with option" do
decorator = CollectionDecorator.new([Product.new], with: OtherDecorator)
expect(*decorator).to be_decorated_with OtherDecorator
end
end
context "when the :with option was not given" do
it "infers the item decorator from each item" do
decorator = CollectionDecorator.new([double(decorate: :inferred_decorator)])
expect(*decorator).to be :inferred_decorator
end
end
end
end
context "when the :with option was not given" do
let(:options) { {} }
describe ".delegate" do
protect_class ProductsDecorator
context "and the decorator can't be inferred from the class" do
let(:subject_class) { Draper::CollectionDecorator }
it "defaults the :to option to :source" do
Object.should_receive(:delegate).with(:foo, :bar, to: :source)
ProductsDecorator.delegate :foo, :bar
end
it "infers the decorator from each item" do
decorator_classes.should == [ProductDecorator, WidgetDecorator]
it "does not overwrite the :to option if supplied" do
Object.should_receive(:delegate).with(:foo, :bar, to: :baz)
ProductsDecorator.delegate :foo, :bar, to: :baz
end
end
describe "#find" do
context "with a block" do
it "decorates Enumerable#find" do
decorator = CollectionDecorator.new([])
decorator.decorated_collection.should_receive(:find).and_return(:delegated)
expect(decorator.find{|p| p.title == "title"}).to be :delegated
end
end
context "and the decorator is inferrable from the class" do
let(:subject_class) { ProductsDecorator}
context "without a block" do
it "decorates Model.find" do
item_decorator = Class.new
decorator = CollectionDecorator.new([], with: item_decorator)
it "infers the decorator" do
decorator_classes.should == [ProductDecorator, ProductDecorator]
item_decorator.should_receive(:find).with(1).and_return(:delegated)
expect(decorator.find(1)).to be :delegated
end
end
end
end
describe ".delegate" do
subject { Class.new(Draper::CollectionDecorator) }
describe "#to_ary" do
# required for `render @collection` in Rails
it "delegates to the decorated collection" do
decorator = CollectionDecorator.new([])
it "defaults the :to option to :source" do
Draper::CollectionDecorator.superclass.should_receive(:delegate).with(:foo, :bar, to: :source)
subject.delegate :foo, :bar
end
it "does not overwrite the :to option if supplied" do
Draper::CollectionDecorator.superclass.should_receive(:delegate).with(:foo, :bar, to: :baz)
subject.delegate :foo, :bar, to: :baz
end
end
describe "#find" do
context "with a block" do
it "decorates Enumerable#find" do
subject.decorated_collection.should_receive(:find)
subject.find {|p| p.title == "title" }
decorator.decorated_collection.should_receive(:to_ary).and_return(:delegated)
expect(decorator.to_ary).to be :delegated
end
end
context "without a block" do
it "decorates Model.find" do
source.should_not_receive(:find)
Product.should_receive(:find).with(1).and_return(:product)
subject.find(1).should == ProductDecorator.new(:product)
it "delegates array methods to the decorated collection" do
decorator = CollectionDecorator.new([])
decorator.decorated_collection.should_receive(:[]).with(42).and_return(:delegated)
expect(decorator[42]).to be :delegated
end
describe "#==" do
context "when comparing to a collection decorator with the same source" do
it "returns true" do
source = [Product.new, Product.new]
decorator = CollectionDecorator.new(source)
other = ProductsDecorator.new(source)
expect(decorator == other).to be_true
end
end
context "when comparing to a collection decorator with a different source" do
it "returns false" do
decorator = CollectionDecorator.new([Product.new, Product.new])
other = ProductsDecorator.new([Product.new, Product.new])
expect(decorator == other).to be_false
end
end
context "when comparing to a collection of the same items" do
it "returns true" do
source = [Product.new, Product.new]
decorator = CollectionDecorator.new(source)
other = source.dup
expect(decorator == other).to be_true
end
end
context "when comparing to a collection of different items" do
it "returns false" do
decorator = CollectionDecorator.new([Product.new, Product.new])
other = [Product.new, Product.new]
expect(decorator == other).to be_false
end
end
context "when the decorated collection has been modified" do
it "is no longer equal to the source" do
source = [Product.new, Product.new]
decorator = CollectionDecorator.new(source)
other = source.dup
decorator << Product.new.decorate
expect(decorator == other).to be_false
end
end
end
describe "#to_s" do
context "when :with option was given" do
it "returns a string representation of the collection decorator" do
decorator = CollectionDecorator.new(["a", "b", "c"], with: ProductDecorator)
expect(decorator.to_s).to eq '#<Draper::CollectionDecorator of ProductDecorator for ["a", "b", "c"]>'
end
end
context "when :with option was not given" do
it "returns a string representation of the collection decorator" do
decorator = CollectionDecorator.new(["a", "b", "c"])
expect(decorator.to_s).to eq '#<Draper::CollectionDecorator of inferred decorators for ["a", "b", "c"]>'
end
end
context "for a custom subclass" do
it "uses the custom class name" do
decorator = ProductsDecorator.new([])
expect(decorator.to_s).to match /ProductsDecorator/
end
end
end
end
describe "#helpers" do
it "returns a HelperProxy" do
subject.helpers.should be_a Draper::HelperProxy
end
it "is aliased to #h" do
subject.h.should be subject.helpers
end
it "initializes the wrapper only once" do
helper_proxy = subject.helpers
helper_proxy.stub(:test_method) { "test_method" }
subject.helpers.test_method.should == "test_method"
subject.helpers.test_method.should == "test_method"
end
end
describe "#localize" do
before { subject.helpers.should_receive(:localize).with(:an_object, {some: 'parameter'}) }
it "delegates to helpers" do
subject.localize(:an_object, some: 'parameter')
end
it "is aliased to #l" do
subject.l(:an_object, some: 'parameter')
end
end
describe ".helpers" do
it "returns a HelperProxy" do
subject.class.helpers.should be_a Draper::HelperProxy
end
it "is aliased to .h" do
subject.class.h.should be subject.class.helpers
end
end
describe "#to_ary" do
# required for `render @collection` in Rails
it "delegates to the decorated collection" do
subject.decorated_collection.stub to_ary: :an_array
subject.to_ary.should == :an_array
end
end
it "delegates array methods to the decorated collection" do
subject.decorated_collection.should_receive(:[]).with(42).and_return(:the_answer)
subject[42].should == :the_answer
end
describe "#==" do
context "when comparing to a collection decorator with the same source" do
it "returns true" do
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
b = ProductsDecorator.new(source)
a.should == b
end
end
context "when comparing to a collection decorator with a different source" do
it "returns false" do
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
b = ProductsDecorator.new([Product.new])
a.should_not == b
end
end
context "when comparing to a collection of the same items" do
it "returns true" do
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
b = source.dup
a.should == b
end
end
context "when comparing to a collection of different items" do
it "returns true" do
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
b = [Product.new]
a.should_not == b
end
end
context "when the decorated collection has been modified" do
it "is no longer equal to the source" do
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
b = source.dup
a << Product.new.decorate
a.should_not == b
end
end
end
describe "#to_s" do
subject { Draper::CollectionDecorator.new(source, options) }
let(:source) { ["a", "b", "c"] }
context "when :with option was given" do
let(:options) { {with: ProductDecorator} }
it "returns a string representation of the CollectionDecorator" do
subject.to_s.should == '#<Draper::CollectionDecorator of ProductDecorator for ["a", "b", "c"]>'
end
end
context "when :with option was not given" do
let(:options) { {} }
it "returns a string representation of the CollectionDecorator" do
subject.to_s.should == '#<Draper::CollectionDecorator of inferred decorators for ["a", "b", "c"]>'
end
end
context "for a custom subclass" do
subject { ProductsDecorator.new(source) }
it "uses the custom class name" do
subject.to_s.should =~ /ProductsDecorator/
end
end
end
end

View File

@ -1,192 +1,190 @@
require 'spec_helper'
describe Draper::Decoratable do
subject { Product.new }
module Draper
describe Decoratable do
describe "#decorate" do
it "returns a decorator for self" do
subject.decorate.should be_a ProductDecorator
subject.decorate.source.should be subject
end
describe "#decorate" do
it "returns a decorator for self" do
product = Product.new
decorator = product.decorate
it "accepts context" do
decorator = subject.decorate(context: {some: 'context'})
decorator.context.should == {some: 'context'}
end
expect(decorator).to be_a ProductDecorator
expect(decorator.source).to be product
end
it "is not memoized" do
subject.decorate.should_not be subject.decorate
end
end
it "accepts context" do
context = {some: "context"}
decorator = Product.new.decorate(context: context)
describe "#applied_decorators" do
it "returns an empty list" do
subject.applied_decorators.should be_empty
end
end
expect(decorator.context).to be context
end
describe "#decorated_with?" do
it "returns false" do
subject.should_not be_decorated_with ProductDecorator
end
end
it "uses the #decorator_class" do
product = Product.new
product.stub decorator_class: OtherDecorator
describe "#decorated?" do
it "returns false" do
subject.should_not be_decorated
end
end
describe "#decorator_class" do
it "delegates to .decorator_class" do
Product.stub(:decorator_class).and_return(WidgetDecorator)
product = Product.new
product.decorator_class.should be WidgetDecorator
end
end
describe "#==" do
context "with itself" do
it "returns true" do
(subject == subject).should be_true
expect(product.decorate).to be_an_instance_of OtherDecorator
end
end
context "with another instance" do
describe "#applied_decorators" do
it "returns an empty list" do
expect(Product.new.applied_decorators).to eq []
end
end
describe "#decorated_with?" do
it "returns false" do
(subject == Product.new).should be_false
expect(Product.new).not_to be_decorated_with Decorator
end
end
context "with a decorated version of itself" do
it "returns true" do
decorator = double(source: subject)
(subject == decorator).should be_true
end
end
context "with a decorated other instance" do
describe "#decorated?" do
it "returns false" do
expect(Product.new).not_to be_decorated
end
end
describe "#decorator_class" do
it "delegates to .decorator_class" do
product = Product.new
Product.should_receive(:decorator_class).and_return(:some_decorator)
expect(product.decorator_class).to be :some_decorator
end
end
describe "#==" do
it "is true for itself" do
product = Product.new
expect(product == product).to be_true
end
it "is false for another instance" do
product = Product.new
expect(product == Product.new).to be_false
end
it "is true for a decorated version of itself" do
product = Product.new
decorator = double(source: product)
expect(product == decorator).to be_true
end
it "is false for a decorated other instance" do
product = Product.new
decorator = double(source: Product.new)
(subject == decorator).should be_false
end
end
end
describe "#===" do
context "with itself" do
it "returns true" do
(subject === subject).should be_true
expect(product == decorator).to be_false
end
end
context "with another instance" do
it "returns false" do
(subject === Product.new).should be_false
describe "#===" do
it "is true when #== is true" do
product = Product.new
product.should_receive(:==).and_return(true)
expect(product === :anything).to be_true
end
it "is false when #== is false" do
product = Product.new
product.should_receive(:==).and_return(false)
expect(product === :anything).to be_false
end
end
context "with a decorated version of itself" do
it "returns true" do
decorator = double(source: subject)
(subject === decorator).should be_true
describe ".====" do
it "is true for an instance" do
expect(Product === Product.new).to be_true
end
end
context "with a decorated other instance" do
it "returns false" do
it "is true for a derived instance" do
expect(Product === Class.new(Product).new).to be_true
end
it "is false for an unrelated instance" do
expect(Product === Model.new).to be_false
end
it "is true for a decorated instance" do
decorator = double(source: Product.new)
(subject === decorator).should be_false
end
end
end
describe ".====" do
context "with an instance" do
it "returns true" do
(Product === Product.new).should be_true
expect(Product === decorator).to be_true
end
it "is true for a decorated derived instance" do
decorator = double(source: Class.new(Product).new)
expect(Product === decorator).to be_true
end
it "is false for a decorated unrelated instance" do
decorator = double(source: Model.new)
expect(Product === decorator).to be_false
end
end
context "with a derived instance" do
it "returns true" do
(Product === Widget.new).should be_true
describe ".decorate" do
it "calls #decorate_collection on .decorator_class" do
scoped = [Product.new]
Product.stub scoped: scoped
Product.decorator_class.should_receive(:decorate_collection).with(scoped, {}).and_return(:decorated_collection)
expect(Product.decorate).to be :decorated_collection
end
it "accepts options" do
options = {context: {some: "context"}}
Product.stub scoped: []
Product.decorator_class.should_receive(:decorate_collection).with([], options)
Product.decorate(options)
end
end
context "with an unrelated instance" do
it "returns false" do
(Product === Object.new).should be_false
describe ".decorator_class" do
context "for classes" do
it "infers the decorator from the class" do
expect(Product.decorator_class).to be ProductDecorator
end
end
context "for ActiveModel classes" do
it "infers the decorator from the model name" do
Product.stub(:model_name).and_return("Other")
expect(Product.decorator_class).to be OtherDecorator
end
end
context "in a namespace" do
context "for classes" do
it "infers the decorator from the class" do
expect(Namespaced::Product.decorator_class).to be Namespaced::ProductDecorator
end
end
context "for ActiveModel classes" do
it "infers the decorator from the model name" do
Namespaced::Product.stub(:model_name).and_return("Namespaced::Other")
expect(Namespaced::Product.decorator_class).to be Namespaced::OtherDecorator
end
end
end
context "when the decorator can't be inferred" do
it "throws an UninferrableDecoratorError" do
expect{Model.decorator_class}.to raise_error UninferrableDecoratorError
end
end
end
context "with a decorated instance" do
it "returns true" do
decorator = double(source: Product.new)
(Product === decorator).should be_true
end
end
context "with a decorated derived instance" do
it "returns true" do
decorator = double(source: Widget.new)
(Product === decorator).should be_true
end
end
context "with a decorated unrelated instance" do
it "returns false" do
decorator = double(source: Object.new)
(Product === decorator).should be_false
end
end
end
describe ".decorate" do
it "returns a collection decorator" do
Product.stub(:scoped).and_return([Product.new])
Product.stub(:decorator_class).and_return(WidgetDecorator)
decorator = Product.decorate
decorator.should be_a Draper::CollectionDecorator
decorator.decorator_class.should be WidgetDecorator
decorator.should == Product.scoped
end
it "accepts context" do
decorator = Product.decorate(context: {some: 'context'})
decorator.context.should == {some: 'context'}
end
it "is not memoized" do
Product.decorate.should_not be Product.decorate
end
end
describe ".decorator_class" do
context "for non-ActiveModel classes" do
it "infers the decorator from the class" do
NonActiveModelProduct.decorator_class.should be NonActiveModelProductDecorator
end
end
context "for ActiveModel classes" do
it "infers the decorator from the model name" do
Product.stub(:model_name).and_return("Widget")
Product.decorator_class.should be WidgetDecorator
end
end
context "for namespaced ActiveModel classes" do
it "infers the decorator from the model name" do
Namespace::Product.decorator_class.should be Namespace::ProductDecorator
end
end
context "when the decorator can't be inferred" do
it "throws an UninferrableDecoratorError" do
expect{UninferrableDecoratorModel.decorator_class}.to raise_error Draper::UninferrableDecoratorError
end
end
end
end

View File

@ -1,142 +1,145 @@
require 'spec_helper'
describe Draper::DecoratedAssociation do
let(:decorated_association) { Draper::DecoratedAssociation.new(owner, :association, options) }
let(:source) { Product.new }
let(:owner) { source.decorate }
let(:options) { {} }
module Draper
describe DecoratedAssociation do
describe "#initialize" do
describe "options validation" do
let(:valid_options) { {with: ProductDecorator, scope: :foo, context: {}} }
it "does not raise error on valid options" do
expect { Draper::DecoratedAssociation.new(owner, :association, valid_options) }.to_not raise_error
end
it "raises error on invalid options" do
expect { Draper::DecoratedAssociation.new(owner, :association, valid_options.merge(foo: 'bar')) }.to raise_error(ArgumentError, /Unknown key/)
end
end
end
describe "#call" do
let(:context) { {foo: "bar"} }
let(:expected_options) { {context: context} }
before do
source.stub association: associated
decorated_association.stub context: context
end
context "for a singular association" do
let(:associated) { Product.new }
let(:decorator) { SpecificProductDecorator }
context "when :with option was given" do
let(:options) { {with: decorator} }
it "uses the specified decorator" do
decorator.should_receive(:decorate).with(associated, expected_options).and_return(:decorated)
decorated_association.call.should be :decorated
describe "#initialize" do
describe "options validation" do
it "does not raise error on valid options" do
valid_options = {with: Decorator, scope: :foo, context: {}}
expect{DecoratedAssociation.new(Decorator.new(Model.new), :association, valid_options)}.not_to raise_error
end
end
context "when :with option was not given" do
it "infers the decorator" do
associated.stub(:decorator_class).and_return(decorator)
decorator.should_receive(:decorate).with(associated, expected_options).and_return(:decorated)
decorated_association.call.should be :decorated
it "raises error on invalid options" do
expect{DecoratedAssociation.new(Decorator.new(Model.new), :association, foo: "bar")}.to raise_error ArgumentError, /Unknown key/
end
end
end
context "for a collection association" do
let(:associated) { [Product.new, Widget.new] }
let(:collection_decorator) { ProductsDecorator }
describe "#call" do
let(:context) { {some: "context"} }
let(:options) { {} }
context "when :with option is a collection decorator" do
let(:options) { {with: collection_decorator} }
let(:decorated_association) do
owner = double(context: nil, source: double(association: associated))
it "uses the specified decorator" do
collection_decorator.should_receive(:decorate).with(associated, expected_options).and_return(:decorated_collection)
decorated_association.call.should be :decorated_collection
DecoratedAssociation.new(owner, :association, options).tap do |decorated_association|
decorated_association.stub context: context
end
end
context "when :with option is a singular decorator" do
let(:options) { {with: decorator} }
let(:decorator) { SpecificProductDecorator }
context "for a singular association" do
let(:associated) { Model.new }
it "uses a CollectionDecorator of the specified decorator" do
decorator.should_receive(:decorate_collection).with(associated, expected_options).and_return(:decorated_collection)
decorated_association.call.should be :decorated_collection
context "when :with option was given" do
let(:options) { {with: Decorator} }
it "uses the specified decorator" do
Decorator.should_receive(:decorate).with(associated, context: context).and_return(:decorated)
expect(decorated_association.call).to be :decorated
end
end
end
context "when :with option was not given" do
context "when the collection is decoratable" do
context "when :with option was not given" do
it "infers the decorator" do
associated.stub(:decorator_class).and_return(collection_decorator)
collection_decorator.should_receive(:decorate).with(associated, expected_options).and_return(:decorated_collection)
decorated_association.call.should be :decorated_collection
end
end
associated.stub decorator_class: OtherDecorator
context "when the collection is not decoratable" do
it "uses a CollectionDecorator of inferred decorators" do
Draper::CollectionDecorator.should_receive(:decorate).with(associated, expected_options).and_return(:decorated_collection)
decorated_association.call.should be :decorated_collection
OtherDecorator.should_receive(:decorate).with(associated, context: context).and_return(:decorated)
expect(decorated_association.call).to be :decorated
end
end
end
end
context "with a scope" do
let(:associated) { [] }
let(:options) { {scope: :foo} }
context "for a collection association" do
let(:associated) { [] }
it "applies the scope before decoration" do
scoped = [Product.new]
associated.should_receive(:foo).and_return(scoped)
decorated_association.call.should == scoped
context "when :with option is a collection decorator" do
let(:options) { {with: ProductsDecorator} }
it "uses the specified decorator" do
ProductsDecorator.should_receive(:decorate).with(associated, context: context).and_return(:decorated_collection)
expect(decorated_association.call).to be :decorated_collection
end
end
context "when :with option is a singular decorator" do
let(:options) { {with: ProductDecorator} }
it "uses a CollectionDecorator of the specified decorator" do
ProductDecorator.should_receive(:decorate_collection).with(associated, context: context).and_return(:decorated_collection)
expect(decorated_association.call).to be :decorated_collection
end
end
context "when :with option was not given" do
context "when the collection itself is decoratable" do
before { associated.stub decorator_class: ProductsDecorator }
it "infers the decorator" do
ProductsDecorator.should_receive(:decorate).with(associated, context: context).and_return(:decorated_collection)
expect(decorated_association.call).to be :decorated_collection
end
end
context "when the collection is not decoratable" do
it "uses a CollectionDecorator of inferred decorators" do
CollectionDecorator.should_receive(:decorate).with(associated, context: context).and_return(:decorated_collection)
expect(decorated_association.call).to be :decorated_collection
end
end
end
end
context "with a scope" do
let(:options) { {scope: :foo} }
let(:associated) { double(foo: scoped) }
let(:scoped) { Product.new }
it "applies the scope before decoration" do
expect(decorated_association.call.source).to be scoped
end
end
end
describe "#context" do
let(:owner_context) { {some: "context"} }
let(:options) { {} }
let(:decorated_association) do
owner = double(context: owner_context)
DecoratedAssociation.new(owner, :association, options)
end
context "when :context option was given" do
let(:options) { {context: context} }
context "and is callable" do
let(:context) { ->(*){ :dynamic_context } }
it "calls it with the owner's context" do
context.should_receive(:call).with(owner_context)
decorated_association.context
end
it "returns the lambda's return value" do
expect(decorated_association.context).to be :dynamic_context
end
end
context "and is not callable" do
let(:context) { {other: "context"} }
it "returns the specified value" do
expect(decorated_association.context).to be context
end
end
end
context "when :context option was not given" do
it "returns the owner's context" do
expect(decorated_association.context).to be owner_context
end
end
end
end
describe "#context" do
before { owner.stub context: :owner_context }
context "when :context option was given" do
let(:options) { {context: context} }
context "and is callable" do
let(:context) { ->(*){ :dynamic_context } }
it "calls it with the owner's context" do
context.should_receive(:call).with(:owner_context)
decorated_association.context
end
it "returns the lambda's return value" do
decorated_association.context.should be :dynamic_context
end
end
context "and is not callable" do
let(:context) { :static_context }
it "returns the specified value" do
decorated_association.context.should be :static_context
end
end
end
context "when :context option was not given" do
it "returns the owner's context" do
decorated_association.context.should be :owner_context
end
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,132 +1,166 @@
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)
module Draper
describe Finders do
protect_class ProductDecorator
before { ProductDecorator.decorates_finders }
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)
expect(decorator).to be_a ProductDecorator
expect(decorator.source).to be found
end
it "passes context to the decorator" do
Product.stub(:find)
context = {some: "context"}
decorator = ProductDecorator.find(1, context: context)
expect(decorator.context).to be context
end
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
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")
expect(decorator).to be_a ProductDecorator
expect(decorator.source).to be found
end
it "proxies complex ProductDecorators" do
Product.should_receive(:find_by_name_and_size).with("apples", "large")
ProductDecorator.find_by_name_and_size("apples", "large")
end
it "proxies find_last_by_(x) ProductDecorators" 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) ProductDecorators" 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) ProductDecorators" 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 "passes context to the decorator" do
Product.stub(:find_by_name_and_size)
context = {some: "context"}
decorator = ProductDecorator.find_by_name_and_size("apples", "large", context: context)
expect(decorator.context).to be context
end
end
it "passes context to the decorator" do
decorator = ProductDecorator.find(1, context: {some: 'context'})
decorator.context.should == {some: 'context'}
end
end
describe ".find_all_by_" do
it "proxies to the model class" do
Product.should_receive(:find_all_by_name_and_size).with("apples", "large").and_return([])
ProductDecorator.find_all_by_name_and_size("apples", "large")
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")
it "decorates the result" do
found = [Product.new, Product.new]
Product.stub(:find_all_by_name).and_return(found)
decorator = ProductDecorator.find_all_by_name("apples")
expect(decorator).to be_a Draper::CollectionDecorator
expect(decorator.decorator_class).to be ProductDecorator
expect(decorator).to eq found
end
it "passes context to the decorator" do
Product.stub(:find_all_by_name)
context = {some: "context"}
decorator = ProductDecorator.find_all_by_name("apples", context: context)
expect(decorator.context).to be context
end
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
describe ".all" do
it "returns a decorated collection" do
found = [Product.new, Product.new]
Product.stub all: found
decorator = ProductDecorator.all
expect(decorator).to be_a Draper::CollectionDecorator
expect(decorator.decorator_class).to be ProductDecorator
expect(decorator).to eq found
end
it "passes context to the decorator" do
Product.stub(:all)
context = {some: "context"}
decorator = ProductDecorator.all(context: context)
expect(decorator.context).to be context
end
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")
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
expect(decorator).to be_a ProductDecorator
expect(decorator.source).to be first
end
it "passes context to the decorator" do
Product.stub(:first)
context = {some: "context"}
decorator = ProductDecorator.first(context: context)
expect(decorator.context).to be context
end
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")
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
expect(decorator).to be_a ProductDecorator
expect(decorator.source).to be last
end
it "passes context to the decorator" do
Product.stub(:last)
context = {some: "context"}
decorator = ProductDecorator.last(context: context)
expect(decorator.context).to be context
end
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 "passes context to the decorator" do
Product.should_receive(:find_by_name_and_size).with("apples", "large", context: {some: 'context'})
decorator = ProductDecorator.find_by_name_and_size("apples", "large", context: {some: 'context'})
decorator.context.should == {some: 'context'}
end
end
describe ".find_all_by_" do
it "proxies to the model class" do
Product.should_receive(:find_all_by_name_and_size).with("apples", "large").and_return([])
ProductDecorator.find_all_by_name_and_size("apples", "large")
end
it "decorates the result" do
found = [Product.new, Product.new]
Product.stub(:find_all_by_name).and_return(found)
decorator = ProductDecorator.find_all_by_name("apples")
decorator.should be_a Draper::CollectionDecorator
decorator.should == found
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 "passes context to the collection decorator" do
collection = ProductDecorator.all(context: {some: 'context'})
collection.context.should == {some: 'context'}
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 "passes context to the decorator" do
decorator = ProductDecorator.first(context: {some: 'context'})
decorator.context.should == {some: 'context'}
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 "passes context to the decorator" do
decorator = ProductDecorator.last(context: {some: 'context'})
decorator.context.should == {some: 'context'}
end
end
end

View File

@ -1,12 +1,14 @@
require 'spec_helper'
describe Draper::HelperProxy do
subject(:helper_proxy) { Draper::HelperProxy.new }
let(:view_context) { Object.new }
before { helper_proxy.stub(:view_context).and_return(view_context) }
module Draper
describe HelperProxy do
it "proxies methods to the view context" do
view_context = double
ViewContext.stub(current: view_context)
helper_proxy = HelperProxy.new
it "proxies methods to the view context" do
view_context.should_receive(:foo).with("bar")
helper_proxy.foo("bar")
view_context.should_receive(:foo).with("bar")
helper_proxy.foo("bar")
end
end
end

View File

@ -1,41 +1,8 @@
require 'spec_helper'
require 'support/shared_examples/view_helpers'
describe Draper::ViewHelpers do
subject(:view_helpers_class) { Class.new { include Draper::ViewHelpers } }
let(:view_helpers) { view_helpers_class.new }
let(:helper_proxy) { Draper::HelperProxy.new }
let(:view_context) { Object.new }
before { view_helpers.helpers.stub(:view_context).and_return(view_context) }
describe "#helpers" do
it "returns a HelperProxy" do
view_helpers.helpers.should be_a Draper::HelperProxy
end
it "is aliased to #h" do
view_helpers.h.should be view_helpers_class.helpers
end
end
it "delegates #localize to #helpers" do
view_context.should_receive(:localize).with(Date.new)
view_helpers.localize(Date.new)
end
it "aliases #l to #localize" do
view_context.should_receive(:localize).with(Date.new)
view_helpers.l(Date.new)
end
describe ".helpers" do
it "returns a HelperProxy" do
view_helpers_class.helpers.should be_a Draper::HelperProxy
end
it "is aliased to #h" do
view_helpers_class.h.should be view_helpers_class.helpers
end
module Draper
describe ViewHelpers do
it_behaves_like "view helpers", Class.new{include ViewHelpers}.new
end
end

View File

@ -1,42 +1,42 @@
require 'spec_helper'
describe PostDecorator do
subject { PostDecorator.new(source) }
let(:decorator) { PostDecorator.new(source) }
let(:source) { Post.create }
it "can use built-in helpers" do
subject.truncated.should == "Once upon a..."
expect(decorator.truncated).to eq "Once upon a..."
end
it "can use built-in private helpers" do
subject.html_escaped.should == "&lt;script&gt;danger&lt;/script&gt;"
expect(decorator.html_escaped).to eq "&lt;script&gt;danger&lt;/script&gt;"
end
it "can use user-defined helpers from app/helpers" do
subject.hello_world.should == "Hello, world!"
expect(decorator.hello_world).to eq "Hello, world!"
end
it "can use path helpers with its model" do
subject.path_with_model.should == "/en/posts/#{source.id}"
expect(decorator.path_with_model).to eq "/en/posts/#{source.id}"
end
it "can use path helpers with its id" do
subject.path_with_id.should == "/en/posts/#{source.id}"
expect(decorator.path_with_id).to eq "/en/posts/#{source.id}"
end
it "can use url helpers with its model" do
subject.url_with_model.should == "http://www.example.com:12345/en/posts/#{source.id}"
expect(decorator.url_with_model).to eq "http://www.example.com:12345/en/posts/#{source.id}"
end
it "can use url helpers with its id" do
subject.url_with_id.should == "http://www.example.com:12345/en/posts/#{source.id}"
expect(decorator.url_with_id).to eq "http://www.example.com:12345/en/posts/#{source.id}"
end
it "can be passed implicitly to url_for" do
subject.link.should == "<a href=\"/en/posts/#{source.id}\">#{source.id}</a>"
expect(decorator.link).to eq "<a href=\"/en/posts/#{source.id}\">#{source.id}</a>"
end
it "serializes overriden attributes" do
subject.serializable_hash["updated_at"].should be :overridden
expect(decorator.serializable_hash["updated_at"]).to be :overridden
end
end

View File

@ -1,19 +1,19 @@
describe "A spec in this folder" do
it "is a decorator spec" do
example.metadata[:type].should be :decorator
expect(example.metadata[:type]).to be :decorator
end
end
describe "A decorator spec" do
it "can access helpers through `helper`" do
helper.content_tag(:p, "Help!").should == "<p>Help!</p>"
expect(helper.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
end
it "can access helpers through `helpers`" do
helpers.content_tag(:p, "Help!").should == "<p>Help!</p>"
expect(helpers.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
end
it "can access helpers through `h`" do
h.content_tag(:p, "Help!").should == "<p>Help!</p>"
expect(h.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
end
end

View File

@ -2,28 +2,28 @@ require 'spec_helper'
describe PostMailer do
describe "#decorated_email" do
subject { Capybara.string(email.body.to_s) }
let(:email_body) { Capybara.string(email.body.to_s) }
let(:email) { PostMailer.decorated_email(post).deliver }
let(:post) { Post.create }
it "decorates" do
subject.should have_content "Today"
expect(email_body).to have_content "Today"
end
it "can use path helpers with a model" do
subject.should have_css "#path_with_model", text: "/en/posts/#{post.id}"
expect(email_body).to have_css "#path_with_model", text: "/en/posts/#{post.id}"
end
it "can use path helpers with an id" do
subject.should have_css "#path_with_id", text: "/en/posts/#{post.id}"
expect(email_body).to have_css "#path_with_id", text: "/en/posts/#{post.id}"
end
it "can use url helpers with a model" do
subject.should have_css "#url_with_model", text: "http://www.example.com:12345/en/posts/#{post.id}"
expect(email_body).to have_css "#url_with_model", text: "http://www.example.com:12345/en/posts/#{post.id}"
end
it "can use url helpers with an id" do
subject.should have_css "#url_with_id", text: "http://www.example.com:12345/en/posts/#{post.id}"
expect(email_body).to have_css "#url_with_id", text: "http://www.example.com:12345/en/posts/#{post.id}"
end
end
end

View File

@ -2,13 +2,13 @@ require 'spec_helper'
describe Post do
describe "#==" do
before { Post.create }
subject { Post.first }
it "is true for other instances' decorators" do
Post.create
one = Post.first
other = Post.first
subject.should_not be other
(subject == other.decorate).should be_true
expect(one).not_to be other
expect(one == other.decorate).to be_true
end
end
end

View File

@ -4,5 +4,6 @@ require 'rspec/rails'
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.expect_with(:rspec) {|c| c.syntax = :expect}
config.order = :random
end

View File

@ -1,4 +1,5 @@
require 'spec_helper'
require 'ammeter/init'
# Generators are not automatically loaded by Rails
require 'generators/decorator/decorator_generator'

View File

@ -10,40 +10,40 @@ app.start_server do
describe "in a #{type}" do
it "runs in the correct environment" do
page.should have_text(app.environment).in("#environment")
expect(page).to have_text(app.environment).in("#environment")
end
it "can use built-in helpers" do
page.should have_text("Once upon a...").in("#truncated")
expect(page).to have_text("Once upon a...").in("#truncated")
end
it "can use built-in private helpers" do
# Nokogiri unescapes text!
page.should have_text("<script>danger</script>").in("#html_escaped")
expect(page).to have_text("<script>danger</script>").in("#html_escaped")
end
it "can use user-defined helpers from app/helpers" do
page.should have_text("Hello, world!").in("#hello_world")
expect(page).to have_text("Hello, world!").in("#hello_world")
end
it "can use user-defined helpers from the controller" do
page.should have_text("Goodnight, moon!").in("#goodnight_moon")
expect(page).to have_text("Goodnight, moon!").in("#goodnight_moon")
end
it "can use path helpers with a model" do
page.should have_text("/en/posts/1").in("#path_with_model")
expect(page).to have_text("/en/posts/1").in("#path_with_model")
end
it "can use path helpers with an id" do
page.should have_text("/en/posts/1").in("#path_with_id")
expect(page).to have_text("/en/posts/1").in("#path_with_id")
end
it "can use url helpers with a model" do
page.should have_text("http://www.example.com:12345/en/posts/1").in("#url_with_model")
expect(page).to have_text("http://www.example.com:12345/en/posts/1").in("#url_with_model")
end
it "can use url helpers with an id" do
page.should have_text("http://www.example.com:12345/en/posts/1").in("#url_with_id")
expect(page).to have_text("http://www.example.com:12345/en/posts/1").in("#url_with_id")
end
end
end

View File

@ -1,29 +1,30 @@
require 'bundler/setup'
require 'ammeter/init'
require 'rails'
require 'draper'
require 'action_view'
require 'action_controller'
require 'action_controller/test_case'
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.expect_with(:rspec) {|c| c.syntax = :expect}
config.order = :random
end
Bundler.require
class Model; include Draper::Decoratable; end
require 'support/active_model'
require 'support/active_record'
require 'support/action_controller'
class Product < Model; end
class ProductDecorator < Draper::Decorator; end
class ProductsDecorator < Draper::CollectionDecorator; end
require 'support/models/product'
require 'support/models/namespaced_product'
require 'support/models/non_active_model_product'
require 'support/models/widget'
require 'support/models/some_thing'
require 'support/models/uninferrable_decorator_model'
class ProductPresenter < Draper::Decorator; end
require 'support/decorators/product_decorator'
require 'support/decorators/namespaced_product_decorator'
require 'support/decorators/non_active_model_product_decorator'
require 'support/decorators/widget_decorator'
require 'support/decorators/specific_product_decorator'
require 'support/decorators/products_decorator'
require 'support/decorators/some_thing_decorator'
require 'support/decorators/decorator_with_application_helper'
class OtherDecorator < Draper::Decorator; end
module Namespaced
class Product < Model; end
class ProductDecorator < Draper::Decorator; end
class OtherDecorator < Draper::Decorator; end
end
# After each example, revert changes made to the class
def protect_class(klass)
before { stub_const klass.name, Class.new(klass) }
end

View File

@ -1,12 +0,0 @@
module ActionController
class Base
Draper.setup_action_controller(self)
end
end
class ApplicationController < ActionController::Base
def hello_world
"Hello, World!"
end
helper_method :hello_world
end

View File

@ -1,7 +0,0 @@
module ActiveModel
module Serialization
def serializable_hash
{overridable: send(:overridable)}
end
end
end

View File

@ -1,9 +0,0 @@
module ActiveRecord
class Base
end
end
module ActiveRecord
class Relation
end
end

View File

@ -1,25 +0,0 @@
class DecoratorWithApplicationHelper < Draper::Decorator
def uses_hello_world
h.hello_world
end
def sample_content
h.content_tag :span, "Hello, World!"
end
def sample_link
h.link_to "Hello", "/World"
end
def sample_truncate
h.truncate("Once upon a time", :length => 7)
end
def length
"overridden"
end
def sample_html_escaped_text
h.html_escape '<script>danger</script>'
end
end

View File

@ -1,5 +0,0 @@
module Namespace
class ProductDecorator < Draper::Decorator
decorates_finders
end
end

View File

@ -1,2 +0,0 @@
class NonActiveModelProductDecorator
end

View File

@ -1,23 +0,0 @@
class ProductDecorator < Draper::Decorator
decorates_finders
def awesome_title
"Awesome Title"
end
def overridable
:overridden
end
def self.overridable
:overridden
end
def self.my_class_method
end
private
def awesome_private_title
end
end

View File

@ -1,10 +0,0 @@
class ProductsDecorator < Draper::CollectionDecorator
def link_to
h.link_to 'sample', "#"
end
def some_method
"some method works"
end
end

View File

@ -1,2 +0,0 @@
class SomeThingDecorator < Draper::Decorator
end

View File

@ -1,2 +0,0 @@
class SpecificProductDecorator < ProductDecorator
end

View File

@ -1,2 +0,0 @@
class WidgetDecorator < ProductDecorator
end

View File

@ -1,49 +0,0 @@
module Namespace
class Product < ActiveRecord::Base
include Draper::Decoratable
def self.first
@@first ||= Namespace::Product.new
end
def self.last
@@last ||= Namespace::Product.new
end
def self.all
[Namespace::Product.new, Namespace::Product.new]
end
def self.scoped
[Namespace::Product.new]
end
def self.model_name
"Namespace::Product"
end
def self.find(id)
return Namespace::Product.new
end
def self.sample_class_method
"sample class method"
end
def hello_world
"Hello, World"
end
def goodnight_moon
"Goodnight, Moon"
end
def title
"Sample Title"
end
def block
yield
end
end
end

View File

@ -1,3 +0,0 @@
class NonActiveModelProduct
include Draper::Decoratable
end

View File

@ -1,95 +0,0 @@
class Product < ActiveRecord::Base
include Draper::Decoratable
include ActiveModel::Serialization
delegate :delegated_method, to: :thing
def self.find_by_name(name)
@@dummy ||= Product.new
end
def self.first
@@first ||= Product.new
end
def self.last
@@last ||= Product.new
end
def self.all
[Product.new, Product.new]
end
def self.scoped
[Product.new]
end
def self.model_name
name
end
def self.find(id)
return Product.new
end
def self.sample_class_method
"sample class method"
end
def hello_world
"Hello, World"
end
def goodnight_moon
"Goodnight, Moon"
end
def title
"Sample Title"
end
def some_action
self.nonexistant_method
end
def block
yield
end
def self.reflect_on_association(association_symbol)
association_symbol.to_s.starts_with?("poro") ? nil : OpenStruct.new(:klass => self)
end
def similar_products
[Product.new, Product.new]
end
def previous_version
Product.new
end
def thing
SomeThing.new
end
def poro_similar_products
[Product.new, Product.new]
end
def poro_previous_version
Product.new
end
def overridable
:overridable
end
def self.overridable
:overridable
end
private
def private_title
end
end

View File

@ -1,5 +0,0 @@
class SomeThing < Product
def delegated_method
'Yay, delegation'
end
end

View File

@ -1,3 +0,0 @@
class UninferrableDecoratorModel
include Draper::Decoratable
end

View File

@ -1,2 +0,0 @@
class Widget < Product
end

View File

@ -0,0 +1,39 @@
shared_examples_for "view helpers" do |subject|
describe "#helpers" do
it "returns the class's helpers" do
expect(subject.helpers).to be subject.class.helpers
end
it "is aliased to #h" do
expect(subject.h).to be subject.helpers
end
end
describe "#localize" do
it "delegates to #helpers" do
subject.helpers.should_receive(:localize).with(:an_object, some: "parameter")
subject.localize(:an_object, some: "parameter")
end
it "is aliased to #l" do
subject.helpers.should_receive(:localize).with(:an_object, some: "parameter")
subject.l(:an_object, some: "parameter")
end
end
describe ".helpers" do
it "returns a HelperProxy" do
expect(subject.class.helpers).to be_a Draper::HelperProxy
end
it "memoizes" do
helpers = subject.class.helpers
expect(subject.class.helpers).to be helpers
end
it "is aliased to .h" do
expect(subject.class.h).to be subject.class.helpers
end
end
end