# encoding: utf-8
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe 'FormHelper' do

  include FormtasticSpecHelper

  before do
    @output_buffer = ActionView::OutputBuffer.new ''
    mock_everything
  end

  describe '#semantic_form_for' do

    it 'yields an instance of Formtastic::FormBuilder' do
      semantic_form_for(@new_post, :url => '/hello') do |builder|
        expect(builder.class).to eq(Formtastic::FormBuilder)
      end
    end

    it 'adds a class of "formtastic" to the generated form' do
      concat(semantic_form_for(@new_post, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.formtastic")
    end

    it 'does not add "novalidate" attribute to the generated form when configured to do so' do
      with_config :perform_browser_validations, true do
        concat(semantic_form_for(@new_post, :url => '/hello') do |builder|
        end)
        expect(output_buffer.to_str).not_to have_tag("form[@novalidate]")
      end
    end

    it 'adds "novalidate" attribute to the generated form when configured to do so' do
      with_config :perform_browser_validations, false do
        concat(semantic_form_for(@new_post, :url => '/hello') do |builder|
        end)
        expect(output_buffer.to_str).to have_tag("form[@novalidate]")
      end
    end

    it 'allows form HTML to override "novalidate" attribute when configured to validate' do
      with_config :perform_browser_validations, false do
        concat(semantic_form_for(@new_post, :url => '/hello', :html => { :novalidate => true }) do |builder|
        end)
        expect(output_buffer.to_str).to have_tag("form[@novalidate]")
      end
    end

    it 'allows form HTML to override "novalidate" attribute when configured to not validate' do
      with_config :perform_browser_validations, true do
        concat(semantic_form_for(@new_post, :url => '/hello', :html => { :novalidate => false }) do |builder|
        end)
        expect(output_buffer.to_str).not_to have_tag("form[@novalidate]")
      end
    end

    it 'adds a class of "xyz" to the generated form' do
      Formtastic::Helpers::FormHelper.default_form_class = 'xyz'
      concat(semantic_form_for(::Post.new, :as => :post, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.xyz")
    end

    it 'omits the leading spaces from the classes in the generated form when the default class is nil' do
      Formtastic::Helpers::FormHelper.default_form_class = nil
      concat(semantic_form_for(::Post.new, :as => :post, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form[class='post']")
    end

    it 'adds class matching the object name to the generated form when a symbol is provided' do
      concat(semantic_form_for(@new_post, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.post")

      concat(semantic_form_for(:project, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.project")
    end

    it 'adds class matching the :as option when provided' do
      concat(semantic_form_for(@new_post, :as => :message, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.message")

      concat(semantic_form_for([:admins, @new_post], :as => :message, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.message")
    end

    it 'adds class matching the object\'s class to the generated form when an object is provided' do
      concat(semantic_form_for(@new_post) do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.post")
    end

    it 'adds a namespaced class to the generated form' do
      concat(semantic_form_for(::Namespaced::Post.new, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.namespaced_post")
    end

    it 'adds a customized class to the generated form' do
      Formtastic::Helpers::FormHelper.default_form_model_class_proc = lambda { |model_class_name| "#{model_class_name}_form" }
      concat(semantic_form_for(@new_post, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.post_form")

      concat(semantic_form_for(:project, :url => '/hello') do |builder|
      end)
      expect(output_buffer.to_str).to have_tag("form.project_form")
    end

    describe 'allows :html options' do
      before(:example) do
        concat(semantic_form_for(@new_post, :url => '/hello', :html => { :id => "something-special", :class => "something-extra", :multipart => true }) do |builder|
        end)
      end

      it 'to add a id of "something-special" to generated form' do
        expect(output_buffer.to_str).to have_tag("form#something-special")
      end

      it 'to add a class of "something-extra" to generated form' do
        expect(output_buffer.to_str).to have_tag("form.something-extra")
      end

      it 'to add enctype="multipart/form-data"' do
        expect(output_buffer.to_str).to have_tag('form[@enctype="multipart/form-data"]')
      end
    end

    it 'can be called with a resource-oriented style' do
      semantic_form_for(@new_post) do |builder|
        expect(builder.object.class).to eq(::Post)
        expect(builder.object_name).to eq("post")
      end
    end

    it 'can be called with a generic style and instance variable' do
      semantic_form_for(@new_post, :as => :post, :url => new_post_path) do |builder|
        expect(builder.object.class).to eq(::Post)
        expect(builder.object_name.to_s).to eq("post") # TODO: is this forced .to_s a bad assumption somewhere?
      end
    end

    it 'can be called with a generic style and inline object' do
      semantic_form_for(@new_post, :url => new_post_path) do |builder|
        expect(builder.object.class).to eq(::Post)
        expect(builder.object_name.to_s).to eq("post") # TODO: is this forced .to_s a bad assumption somewhere?
      end
    end

    describe 'ActionView::Base.field_error_proc' do
      around do |ex|
        error_proc = Formtastic::Helpers::FormHelper.formtastic_field_error_proc
        ex.run
        Formtastic::Helpers::FormHelper.formtastic_field_error_proc = error_proc
      end

      it 'is set to no-op wrapper by default' do
        semantic_form_for(@new_post, :url => '/hello') do |builder|
          expect(::ActionView::Base.field_error_proc.call("html", nil)).to eq("html")
        end
      end

      it 'is set to the configured custom field_error_proc' do
        field_error_proc = double()
        Formtastic::Helpers::FormHelper.formtastic_field_error_proc = field_error_proc
        semantic_form_for(@new_post, :url => '/hello') do |builder|
          expect(::ActionView::Base.field_error_proc).to eq(field_error_proc)
        end
      end

      it 'is restored to its original value after the form is rendered' do
        expect do
          Formtastic::Helpers::FormHelper.formtastic_field_error_proc = proc {""}
          semantic_form_for(@new_post, :url => '/hello') { |builder| }
        end.not_to change(::ActionView::Base, :field_error_proc)
      end
    end

    describe "with :builder option" do
      it "yields an instance of the given builder" do
        class MyAwesomeCustomBuilder < Formtastic::FormBuilder
        end
        semantic_form_for(@new_post, :url => '/hello', :builder => MyAwesomeCustomBuilder) do |builder|
          expect(builder.class).to eq(MyAwesomeCustomBuilder)
        end
      end
    end

    describe 'with :namespace option' do
      it "should set the custom_namespace" do
        semantic_form_for(@new_post, :namespace => 'context2') do |builder|
          expect(builder.dom_id_namespace).to eq('context2')
        end
      end
    end

    describe 'without :namespace option' do
      it 'defaults to class settings' do
        expect(Formtastic::FormBuilder).to receive(:custom_namespace).and_return('context2')

        semantic_form_for(@new_post) do |builder|
          expect(builder.dom_id_namespace).to eq('context2')
        end
      end
    end

  end

  describe '#semantic_fields_for' do
    it 'yields an instance of Formtastic::FormBuilder' do
      semantic_fields_for(@new_post) do |builder|
        expect(builder.class).to be(Formtastic::FormBuilder)
      end
    end
  end

end

