require 'spec_helper'
require_relative '../dummy/app/decorators/post_decorator'

Post = Struct.new(:id) { }

module Draper
  describe QueryMethods do
    let(:fake_strategy) { instance_double(QueryMethods::LoadStrategy::ActiveRecord) }

    before { allow(QueryMethods::LoadStrategy).to receive(:new).and_return(fake_strategy) }

    describe '#method_missing' do
      let(:collection) { [ Post.new, Post.new ] }
      let(:collection_context) { { user: 'foo' } }
      let(:collection_decorator) { PostDecorator.decorate_collection(collection, context: collection_context) }

      context 'when strategy allows collection to call the method' do
        let(:results) { spy(:results) }

        before do
          allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(true)
          allow(collection).to receive(:send).with(:some_query_method).and_return(results)
        end

        it 'calls the method on the collection and decorate it results' do
          collection_decorator.some_query_method

          expect(results).to have_received(:decorate)
        end

        it 'calls the method on the collection and keeps the decoration options' do
          collection_decorator.some_query_method

          expect(results).to have_received(:decorate).with({ context: collection_context, with: PostDecorator })
        end
      end

      context 'when strategy does not allow collection to call the method' do
        before { allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(false) }

        it 'raises NoMethodError' do
          expect { collection_decorator.some_query_method }.to raise_exception(NoMethodError)
        end
      end
    end

    describe "#respond_to?" do
      let(:collection) { [ Post.new, Post.new ] }
      let(:collection_decorator) { PostDecorator.decorate_collection(collection) }

      subject { collection_decorator.respond_to?(:some_query_method) }

      context 'when strategy allows collection to call the method' do
        before do
          allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(true)
          allow(collection).to receive(:respond_to?).with(:some_query_method).and_return(true)
        end

        it { is_expected.to eq(true) }

        context 'and collection does not implement the method' do
          before do
            allow(collection).to receive(:respond_to?).with(:some_query_method).and_return(false)
          end

          it { is_expected.to eq(false) }
        end
      end

      context 'when strategy does not allow collection to call the method' do
        before do
          allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(false)
          allow(collection).to receive(:respond_to?).with(:some_query_method).and_return(true)
        end

        it { is_expected.to eq(false) }
      end
    end
  end
end
