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:
parent
fa2d5274a6
commit
2bfa25a5ad
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 == "<script>danger</script>"
|
||||
expect(decorator.html_escaped).to eq "<script>danger</script>"
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'spec_helper'
|
||||
require 'ammeter/init'
|
||||
|
||||
# Generators are not automatically loaded by Rails
|
||||
require 'generators/decorator/decorator_generator'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -1,7 +0,0 @@
|
|||
module ActiveModel
|
||||
module Serialization
|
||||
def serializable_hash
|
||||
{overridable: send(:overridable)}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
module ActiveRecord
|
||||
class Base
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveRecord
|
||||
class Relation
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||
module Namespace
|
||||
class ProductDecorator < Draper::Decorator
|
||||
decorates_finders
|
||||
end
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class NonActiveModelProductDecorator
|
||||
end
|
|
@ -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
|
|
@ -1,10 +0,0 @@
|
|||
class ProductsDecorator < Draper::CollectionDecorator
|
||||
|
||||
def link_to
|
||||
h.link_to 'sample', "#"
|
||||
end
|
||||
|
||||
def some_method
|
||||
"some method works"
|
||||
end
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class SomeThingDecorator < Draper::Decorator
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class SpecificProductDecorator < ProductDecorator
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class WidgetDecorator < ProductDecorator
|
||||
end
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
class NonActiveModelProduct
|
||||
include Draper::Decoratable
|
||||
end
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||
class SomeThing < Product
|
||||
def delegated_method
|
||||
'Yay, delegation'
|
||||
end
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
class UninferrableDecoratorModel
|
||||
include Draper::Decoratable
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class Widget < Product
|
||||
end
|
|
@ -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
|
Loading…
Reference in New Issue