require 'spec_helper' describe Datagrid::Columns do let(:group) { Group.create!(:name => "Pop") } subject do SimpleReport.new end describe "basic methods" do let!(:entry) { Entry.create!( :group => group, :name => "Star", :disabled => false, :confirmed => false, :category => "first", :access_level => 'admin', :pet => 'rottweiler', :shipping_date => Date.new(2013, 8, 1) ) } let(:date) { Date.new(2013, 8, 1) } it "should have data columns without html columns" do expect(subject.data_columns.size).to eq(subject.columns.size - 1) end it "should build rows of data" do expect(subject.rows).to eq([[date, "Pop", "Star", "admin", "ROTTWEILER"]]) end it "should generate header" do expect(subject.header).to eq(["Shipping date", "Group", "Name", "Access level", "Pet"]) end it "should return html_columns" do report = test_report do scope {Entry} column(:id) column(:name, :html => false) end expect(report.html_columns.map(&:name)).to eq([:id]) end it "should return html_columns when column definition has 2 arguments" do report = test_report(:name => "Hello") do scope {Entry} filter(:name) column(:id) column(:name, :html => false) do |model, grid| "'#{model.name}' filtered by '#{grid.name}'" end end entry = Entry.create!(:name => "Hello World") expect(report.row_for(entry)).to eq([entry.id, "'Hello World' filtered by 'Hello'"]) end it "should generate table data" do expect(subject.data).to eq([ subject.header, subject.row_for(entry) ]) end it "should generate hash for given asset" do expect(subject.hash_for(entry)).to eq({ :group => "Pop", :name => "Star", :access_level => 'admin', :pet => 'ROTTWEILER', :shipping_date => date }) end it "should support csv export" do expect(subject.to_csv).to eq("Shipping date,Group,Name,Access level,Pet\n#{date},Pop,Star,admin,ROTTWEILER\n") end it "should support csv export of particular columns" do expect(subject.to_csv(:name)).to eq("Name\nStar\n") end it "should support csv export options" do expect(subject.to_csv(:col_sep => ";")).to eq("Shipping date;Group;Name;Access level;Pet\n#{date};Pop;Star;admin;ROTTWEILER\n") end end it "should support columns with model and report arguments" do report = test_report(:category => "foo") do scope {Entry.order(:category)} filter(:category) do |value| where("category LIKE '%#{value}%'") end column(:exact_category) do |entry, grid| entry.category == grid.category end end Entry.create!(:category => "foo") Entry.create!(:category => "foobar") expect(report.rows.first.first).to eq(true) expect(report.rows.last.first).to eq(false) end it "should inherit columns correctly" do parent = Class.new do include Datagrid scope { Entry } column(:name) end child = Class.new(parent) do column(:group_id) end expect(parent.column_by_name(:name)).not_to be_nil expect(parent.column_by_name(:group_id)).to be_nil expect(child.column_by_name(:name)).not_to be_nil expect(child.column_by_name(:group_id)).not_to be_nil end it "should support defining a query for a column" do report = test_report do scope {Entry} filter(:name) column(:id) column(:sum_group_id, 'sum(group_id)') end Entry.create!(:group => group) expect(report.assets.first.sum_group_id).to eq(group.id) end it "should support post formatting for column defined with query" do report = test_report do scope {Group.joins(:entries).group("groups.id")} filter(:name) column(:entries_count, 'count(entries.id)') do |model| format("(#{model.entries_count})") do |value| content_tag(:span, value) end end end 3.times { Entry.create!(group: group) } expect(report.rows).to eq([["(3)"]]) end it "should support hidding columns through if and unless" do report = test_report do scope {Entry} column(:id, :if => :show?) column(:name, :unless => proc {|grid| !grid.show? }) column(:category) def show? false end end expect(report.columns(:id)).to eq([]) expect(report.columns(:name)).to eq([]) expect(report.available_columns.map(&:name)).to eq([:category]) end describe ".column_names attributes" do let(:grid) do test_report(:column_names => ["id", "name"]) do scope { Entry } column(:id) column(:name) column(:category) end end let!(:entry) do Entry.create!(:name => 'hello') end it "should be suppored in header" do expect(grid.header).to eq(["Id", "Name"]) end it "should be suppored in rows" do expect(grid.rows).to eq([[entry.id, "hello"]]) end it "should be suppored in csv" do expect(grid.to_csv).to eq("Id,Name\n#{entry.id},hello\n") end it "should support explicit overwrite" do expect(grid.header(:id, :name, :category)).to eq(%w(Id Name Category)) end end context "when grid has formatted column" do it "should output correct data" do report = test_report do scope {Entry} column(:name) do |entry| format(entry.name) do |value| "#{value} "Hello World") expect(report.rows).to eq([["Hello World"]]) end end describe ".default_column_options" do it "should pass default options to each column definition" do report = test_report do scope {Entry} self.default_column_options = {:order => false} column(:id) column(:name, :order => "name") end first = Entry.create(:name => '1st') second = Entry.create(:name => '2nd') expect { report.attributes = {:order => :id} }.to raise_error(Datagrid::OrderUnsupported) report.attributes = {:order => :name, :descending => true} expect(report.assets).to eq([second, first]) end end describe "fetching data in batches" do it "should pass the batch size to the find_each method" do report = test_report do scope { Entry } column :id self.batch_size = 25 end fake_assets = double(:assets) expect(report).to receive(:assets) { fake_assets } expect(fake_assets).to receive(:find_each).with(batch_size: 25) report.rows end it "should be able to disable batches" do report = test_report do scope { Entry } column :id self.batch_size = 0 end fake_assets = double(:assets) expect(report).to receive(:assets) { fake_assets } expect(fake_assets).to receive(:each) expect(fake_assets).not_to receive(:find_each) report.rows end it "should support instance level batch size" do grid = test_report do scope {Entry} column :id self.batch_size = 25 end grid.batch_size = 0 fake_assets = double(:assets) expect(grid).to receive(:assets) { fake_assets } expect(fake_assets).to receive(:each) expect(fake_assets).not_to receive(:find_each) grid.rows end end describe ".data_row" do it "should give access to column values via an object" do grid = test_report do scope { Entry } column(:id) column(:name) do name.capitalize end column(:actions, html: true) do "some link here" end end entry = Entry.create!(name: 'hello') row = grid.data_row(entry) expect(row.id).to eq(entry.id) expect(row.name).to eq("Hello") expect { row.actions }.to raise_error end end describe "column value" do it "should support conversion" do group = Group.create! Entry.create(:group => group) Entry.create(:group => group) grid = test_report do scope { Group } column(:entries_count) do |g| g.entries.count end column(:odd_entries) do |_, _, row| row.entries_count.odd? end end expect(grid.row_for(group)).to eq([2, false]) end end describe "instance level column definition" do let(:modified_grid) do grid = test_report do scope { Entry } column(:id) end grid.column(:name) grid end let(:basic_grid) { modified_grid.class.new } let!(:entry) { Entry.create!(:name => "Hello", :category => 'first') } it "should have correct columns" do expect(modified_grid.columns.size).to eq(2) expect(basic_grid.class.columns.size).to eq(1) expect(basic_grid.columns.size).to eq(1) end it "should give correct header" do expect(modified_grid.header).to eq(["Id", "Name"]) expect(basic_grid.header).to eq(["Id"]) end it "should give correct rows" do expect(modified_grid.rows).to eq([[entry.id, 'Hello']]) expect(basic_grid.rows).to eq([[entry.id]]) end it "should support possitioning" do modified_grid.column(:category, :before => :name) expect(modified_grid.header).to eq(["Id", "Category", "Name"]) end it "should support columns block" do modified_grid.column(:category) do category.capitalize end expect(modified_grid.rows).to eq([[entry.id, "Hello", 'First']]) end it "should support column_names accessor" do modified_grid.column_names = [:name] expect(modified_grid.rows).to eq([['Hello']]) modified_grid.column_names = [:id] expect(modified_grid.rows).to eq([[entry.id]]) end it "should support column_names accessor with mandatory columns" do modified_grid.column(:category, :mandatory => true) modified_grid.column_names = [:name] expect(modified_grid.rows).to eq([['Hello', 'first']]) basic_grid.column_names = [:id] expect(basic_grid.rows).to eq([[entry.id]]) end it "should support available columns" do modified_grid.column(:category, :mandatory => true) expect(modified_grid.available_columns.map(&:name)).to eq([:id, :name, :category]) end it "should respect column availability criteria" do modified_grid.column(:category, :if => proc { false }) expect(modified_grid.columns.map(&:name)).to eq([:id, :name]) end end describe 'dynamic helper' do it "should work" do grid = test_report do scope {Entry} column(:id) dynamic { column(:name) column(:category) } end expect(grid.columns.map(&:name)).to eq([:id, :name, :category]) expect(grid.class.columns.map(&:name)).to eq([:id]) expect(grid.column_by_name(:id)).not_to be_nil expect(grid.column_by_name(:name)).not_to be_nil end it "has access to attributes" do grid = test_report(:attribute_name => 'value') do scope {Entry} datagrid_attribute :attribute_name dynamic { value = attribute_name column(:name) { value } } end expect(grid.data_value(:name, Entry.create!)).to eq('value') end end describe ".data_value" do it "should return value" do grid = test_report do scope {Entry } column(:name) end expect(grid.data_value(:name, Entry.create!(:name => 'Hello'))).to eq('Hello') end it "should raise for disabled columns" do grid = test_report do scope {Entry } column(:name, :if => proc { false }) end expect { grid.data_value(:name, Entry.create!(:name => 'Hello')) }.to raise_error(Datagrid::ColumnUnavailableError) end end describe "caching" do it "should work when enabled in class" do grid = test_report do scope {Entry} self.cached = true column(:random1) {rand(10**9)} column(:random2) {rand(10**9)} end row = grid.data_row(Entry.create!) expect(row.random1).to eq(row.random1) expect(row.random2).to_not eq(row.random1) grid.cached = false expect(row.random2).to_not eq(row.random2) expect(row.random2).to_not eq(row.random1) end end end