require 'spec_helper'

RSpec.describe RailsAdmin::ApplicationHelper, type: :helper do
  describe '#authorized?' do
    let(:abstract_model) { RailsAdmin.config(FieldTest).abstract_model }

    it 'doesn\'t use unpersisted objects' do
      expect(helper).to receive(:action).with(:edit, abstract_model, nil).and_call_original
      helper.authorized?(:edit, abstract_model, FactoryBot.build(:field_test))
    end
  end

  describe 'with #authorized? stubbed' do
    before do
      allow(controller).to receive(:authorized?).and_return(true)
    end

    describe '#current_action?' do
      it 'returns true if current_action, false otherwise' do
        @action = RailsAdmin::Config::Actions.find(:index)

        expect(helper.current_action?(RailsAdmin::Config::Actions.find(:index))).to be_truthy
        expect(helper.current_action?(RailsAdmin::Config::Actions.find(:show))).not_to be_truthy
      end
    end

    describe '#action' do
      it 'returns action by :custom_key' do
        RailsAdmin.config do |config|
          config.actions do
            dashboard do
              custom_key :my_custom_dashboard_key
            end
          end
        end
        expect(helper.action(:my_custom_dashboard_key)).to be
      end

      it 'returns only visible actions' do
        RailsAdmin.config do |config|
          config.actions do
            dashboard do
              visible false
            end
          end
        end

        expect(helper.action(:dashboard)).to be_nil
      end

      it 'returns only visible actions, passing all bindings' do
        RailsAdmin.config do |config|
          config.actions do
            member :test_bindings do
              visible do
                bindings[:controller].is_a?(ActionView::TestCase::TestController) &&
                  bindings[:abstract_model].model == Team &&
                  bindings[:object].is_a?(Team)
              end
            end
          end
        end
        expect(helper.action(:test_bindings, RailsAdmin::AbstractModel.new(Team), Team.new)).to be
        expect(helper.action(:test_bindings, RailsAdmin::AbstractModel.new(Team), Player.new)).to be_nil
        expect(helper.action(:test_bindings, RailsAdmin::AbstractModel.new(Player), Team.new)).to be_nil
      end
    end

    describe '#actions' do
      it 'returns actions by type' do
        abstract_model = RailsAdmin::AbstractModel.new(Player)
        object = FactoryBot.create :player
        expect(helper.actions(:all, abstract_model, object).collect(&:custom_key)).to eq([:dashboard, :index, :show, :new, :edit, :export, :delete, :bulk_delete, :history_show, :history_index, :show_in_app])
        expect(helper.actions(:root, abstract_model, object).collect(&:custom_key)).to eq([:dashboard])
        expect(helper.actions(:collection, abstract_model, object).collect(&:custom_key)).to eq([:index, :new, :export, :bulk_delete, :history_index])
        expect(helper.actions(:member, abstract_model, object).collect(&:custom_key)).to eq([:show, :edit, :delete, :history_show, :show_in_app])
      end

      it 'only returns visible actions, passing bindings correctly' do
        RailsAdmin.config do |config|
          config.actions do
            member :test_bindings do
              visible do
                bindings[:controller].is_a?(ActionView::TestCase::TestController) &&
                  bindings[:abstract_model].model == Team &&
                  bindings[:object].is_a?(Team)
              end
            end
          end
        end

        expect(helper.actions(:all, RailsAdmin::AbstractModel.new(Team), Team.new).collect(&:custom_key)).to eq([:test_bindings])
        expect(helper.actions(:all, RailsAdmin::AbstractModel.new(Team), Player.new).collect(&:custom_key)).to eq([])
        expect(helper.actions(:all, RailsAdmin::AbstractModel.new(Player), Team.new).collect(&:custom_key)).to eq([])
      end
    end

    describe '#logout_method' do
      it 'defaults to :delete when Devise is not defined' do
        allow(Object).to receive(:defined?).with(Devise).and_return(false)

        expect(helper.logout_method).to eq(:delete)
      end

      it 'uses first sign out method from Devise when it is defined' do
        allow(Object).to receive(:defined?).with(Devise).and_return(true)

        expect(Devise).to receive(:sign_out_via).and_return([:whatever_defined_on_devise, :something_ignored])
        expect(helper.logout_method).to eq(:whatever_defined_on_devise)
      end
    end

    describe '#wording_for' do
      it 'gives correct wording even if action is not visible' do
        RailsAdmin.config do |config|
          config.actions do
            index do
              visible false
            end
          end
        end

        expect(helper.wording_for(:menu, :index)).to eq('List')
      end

      it 'passes correct bindings' do
        expect(helper.wording_for(:title, :edit, RailsAdmin::AbstractModel.new(Team), Team.new(name: 'the avengers'))).to eq("Edit Team 'the avengers'")
      end

      it 'defaults correct bindings' do
        @action = RailsAdmin::Config::Actions.find :edit
        @abstract_model = RailsAdmin::AbstractModel.new(Team)
        @object = Team.new(name: 'the avengers')
        expect(helper.wording_for(:title)).to eq("Edit Team 'the avengers'")
      end

      it 'does not try to use the wrong :label_metod' do
        @abstract_model = RailsAdmin::AbstractModel.new(Draft)
        @object = Draft.new

        expect(helper.wording_for(:link, :new, RailsAdmin::AbstractModel.new(Team))).to eq('Add a new Team')
      end
    end

    describe '#breadcrumb' do
      it 'gives us a breadcrumb' do
        @action = RailsAdmin::Config::Actions.find(:edit, abstract_model: RailsAdmin::AbstractModel.new(Team), object: FactoryBot.create(:team, name: 'the avengers'))
        bc = helper.breadcrumb
        expect(bc).to match(/Dashboard/) # dashboard
        expect(bc).to match(/Teams/) # list
        expect(bc).to match(/the avengers/) # show
        expect(bc).to match(/Edit/) # current (edit)
      end
    end

    describe '#menu_for' do
      it 'passes model and object as bindings and generates a menu, excluding non-get actions' do
        RailsAdmin.config do |config|
          config.actions do
            dashboard
            index do
              visible do
                bindings[:abstract_model].model == Team
              end
            end
            show do
              visible do
                bindings[:object].class == Team
              end
            end
            delete do
              http_methods [:post, :put, :delete]
            end
          end
        end

        @action = RailsAdmin::Config::Actions.find :show
        @abstract_model = RailsAdmin::AbstractModel.new(Team)
        @object = FactoryBot.create(:team, name: 'the avengers')

        expect(helper.menu_for(:root)).to match(/Dashboard/)
        expect(helper.menu_for(:collection, @abstract_model)).to match(/List/)
        expect(helper.menu_for(:member, @abstract_model, @object)).to match(/Show/)

        @abstract_model = RailsAdmin::AbstractModel.new(Player)
        @object = Player.new
        expect(helper.menu_for(:collection, @abstract_model)).not_to match(/List/)
        expect(helper.menu_for(:member, @abstract_model, @object)).not_to match(/Show/)
      end

      it 'excludes non-get actions' do
        RailsAdmin.config do |config|
          config.actions do
            dashboard do
              http_methods [:post, :put, :delete]
            end
          end
        end

        @action = RailsAdmin::Config::Actions.find :dashboard
        expect(helper.menu_for(:root)).not_to match(/Dashboard/)
      end

      it 'shows actions which are marked as show_in_menu' do
        I18n.backend.store_translations(
          :en, admin: {actions: {
            shown_in_menu: {menu: 'Look this'},
          }}
        )
        RailsAdmin.config do |config|
          config.actions do
            dashboard do
              show_in_menu false
            end
            root :shown_in_menu, :dashboard do
              action_name :dashboard
              show_in_menu true
            end
          end
        end

        @action = RailsAdmin::Config::Actions.find :dashboard
        expect(helper.menu_for(:root)).not_to match(/Dashboard/)
        expect(helper.menu_for(:root)).to match(/Look this/)
      end
    end

    describe '#main_navigation' do
      it 'shows included models' do
        RailsAdmin.config do |config|
          config.included_models = [Ball, Comment]
        end
        expect(helper.main_navigation).to match(/(dropdown-header).*(Navigation).*(Balls).*(Comments)/m)
      end

      it 'does not draw empty navigation labels' do
        RailsAdmin.config do |config|
          config.included_models = [Ball, Comment, Comment::Confirmed]
          config.model Comment do
            navigation_label 'Commentz'
          end
          config.model Comment::Confirmed