require 'spec_helper' require 'ostruct' module Admino module Table describe Presenter do subject(:presenter) { presenter_klass.new(collection, Post, query, view) } let(:presenter_klass) { Presenter } let(:query) { double('Query') } let(:view) { RailsViewContext.new } let(:collection) { [ first_post, second_post ] } let(:first_post) { Post.new('1') } let(:second_post) { Post.new('2') } let(:head_row) { double('HeadRow', to_html: ''.html_safe) } let(:resource_row) { double('ResourceRow', to_html: ''.html_safe) } before do HeadRow.stub(:new).with(Post, query, view).and_return(head_row) ResourceRow.stub(:new).with(first_post, view).and_return(resource_row) ResourceRow.stub(:new).with(second_post, view).and_return(resource_row) end describe '#.to_html' do let(:result) { presenter.to_html } it 'outputs a table' do expect(result).to have_tag(:table) end it 'outputs a thead with a single row' do expect(result).to have_tag('table thead tr') end it 'outputs a tbody with a row for each collection member' do expect(result).to have_tag('table tbody tr', count: 2) end context 'if the record responds to #dom_id' do before do first_post.stub(:dom_id).and_return('post_1') second_post.stub(:dom_id).and_return('post_2') end it 'adds a record identifier to each collection row' do expect(result).to have_tag('tbody tr#post_1:first-child') expect(result).to have_tag('tbody tr#post_2:last-child') end end it 'adds zebra classes to each collection row' do expect(result).to have_tag('tbody tr.is-even:first-child') expect(result).to have_tag('tbody tr.is-odd:last-child') end it 'delegates thead columns creation to .to_html HeadRow' do expect(result).to have_tag('thead tr td#thead_td') end it 'delegates tbody columns creation to .to_html ResourceRow' do expect(result).to have_tag('tbody tr td#tbody_td') end it 'allows passing table HTML options' do expect(presenter.to_html(id: 'table')).to have_tag(:table, with: { id: 'table' }) end context 'with a block' do let(:block_call_args) do block_call_args = [] presenter.to_html do |*args| block_call_args << args end block_call_args end it 'calls it once passing the HeadRow instance' do expect(block_call_args[0]).to eq [head_row, nil] end it 'calls it once for each collection member passing the ResourceRow instance and the member itself' do expect(block_call_args[1]).to eq [resource_row, first_post] expect(block_call_args[2]).to eq [resource_row, second_post] end end context 'custom table HTML options' do let(:presenter_klass) do Class.new(Presenter) do private def table_html_options { id: 'table' } end def thead_html_options { id: 'thead' } end def thead_tr_html_options { id: 'thead_tr' } end def tbody_html_options { id: 'tbody' } end def tbody_tr_html_options(resource, index) { class: "index-#{index}" } end def zebra_css_classes %w(one two) end end end it "allows customizing the default table html attributes" do expect(presenter.to_html).to have_tag(:table, with: { id: 'table' }) end it "allows customizing the the default thead html attributes" do expect(presenter.to_html).to have_tag(:thead, with: { id: 'thead' }) end it "allows customizing the the default thead_tr html attributes" do expect(presenter.to_html).to have_tag('thead tr#thead_tr') end it "allows customizing the the default tbody html attributes" do expect(presenter.to_html).to have_tag(:tbody, with: { id: 'tbody' }) end it "allows customizing the tbody_tr html attributes" do expect(presenter.to_html).to have_tag("tbody tr.index-0:first-child") end it 'allows customizing zebra classes' do expect(presenter.to_html).to have_tag("tbody tr.one:first-child") end end context 'custom row builders' do let(:presenter_klass) do Class.new(Presenter) do private def head_row(*args) OpenStruct.new(to_html: ''.html_safe) end def resource_row(*args) OpenStruct.new(to_html: ''.html_safe) end end end it 'allows customizing head row renderers' do expect(presenter.to_html).to have_tag('thead tr td#custom_thead_td') end it 'allows customizing resource row renderers' do expect(presenter.to_html).to have_tag('tbody tr td#custom_tbody_td') end end end end end end