Files
openfoodnetwork/spec/lib/reports/report_spec.rb
2024-05-09 12:24:41 +10:00

325 lines
9.9 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
# rubocop:disable Metrics/ModuleLength
module Reporting
RSpec.describe ReportTemplate do
let(:user) { create(:user) }
let(:params) { {} }
subject { described_class.new(user, params) }
# rubocop:disable Metrics/AbcSize
def check_report
# Mock using instance variables
allow(subject).to receive(:columns).and_return(@columns)
allow(subject).to receive(:query_result).and_return(@query_result)
allow(subject).to receive(:rules).and_return(@rules) if @rules.present?
if @custom_headers.present?
allow(subject).to receive(:custom_headers).and_return(@custom_headers)
end
# Check result depending on existing instance variables
expect(subject.rows.map(&:to_h)).to eq(@expected_rows) if @expected_rows.present?
expect(subject.table_rows).to eq(@expected_table_rows) if @expected_table_rows.present?
expect(subject.table_headers).to eq(@expected_headers) if @expected_headers.present?
end
# rubocop:enable Metrics/AbcSize
describe ".default_params" do
it "use correctly the default values" do
default_params = {
filter: "default__filter",
other_filter: "default_other_filter",
q: { hub: "default_hub", customer: "default_customer" }
}
real_params = {
filter: "test_filter",
q: { hub: "test_hub" }
}
expected_params = {
filter: "test_filter",
other_filter: "default_other_filter",
q: { hub: "test_hub", customer: "default_customer" }
}
allow_any_instance_of(described_class).to receive(:default_params)
.and_return(default_params)
report = described_class.new(user, real_params)
expect(report.params).to eq(expected_params)
end
end
describe ".columns" do
before do
@query_result = [
OpenStruct.new(hub: { name: "My Hub" }, product: { name: "Apple", price: 5 })
]
end
it "handle procs" do
@columns = {
hub: proc { |item| item.hub[:name] }
}
@expected_rows = [
{ hub: "My Hub" }
]
check_report
end
it "handles symbols" do
@columns = {
hub: :hub_name
}
allow(subject).to receive(:hub_name).and_return("Transformed Hub Name")
@expected_rows = [
{ hub: "Transformed Hub Name" }
]
check_report
end
end
describe ".table_headers" do
before do
@columns = {
hub: proc { |item| item.hub[:name] },
product: proc { |item| item.product[:name] },
price: proc { |item| item.product[:price] },
}
end
it "uses the columns keys" do
@expected_headers = ['Hub', 'Product', 'Price']
check_report
end
it "handles custom_headers" do
@custom_headers = {
product: 'Custom Product',
not_existing_key: "My Key"
}
@expected_headers = ['Hub', 'Custom Product', 'Price']
check_report
end
describe "fields_to_show" do
let(:params) { { fields_to_show: [:hub, :price] } }
it "works" do
@expected_headers = ['Hub', 'Price']
check_report
end
end
end
describe ".table_rows" do
before do
@columns = {
price: proc { |item| item.product[:price] },
hub: proc { |item| item.hub[:name] }
}
@query_result = [
OpenStruct.new(hub: { name: "My Hub" }, product: { name: "Apple", price: 5 }),
OpenStruct.new(hub: { name: "My Other Hub" }, product: { name: "Apple", price: 12 })
]
end
it "get correct data" do
allow(subject).to receive(:unformatted_render?).and_return(true)
@expected_table_rows = [
[5, "My Hub"],
[12, "My Other Hub"],
]
check_report
end
context "when report contains duplicate rows" do
before do
@columns = {
customer: proc { |item| item.customer },
address: proc { |item| item.address }
}
@query_result = [
OpenStruct.new(customer: "John", address: "1 Main Street"),
OpenStruct.new(customer: "John", address: "1 Main Street")
]
end
context "and the report type allows duplicate rows i.e. the default behaviour" do
it "outputs duplicate rows" do
@expected_table_rows = [
["John", "1 Main Street"],
["John", "1 Main Street"]
]
check_report
end
end
context "and the report type does not allow duplicate rows" do
before { allow(subject).to receive(:skip_duplicate_rows?).and_return(true) }
it "outputs only unique rows" do
@expected_table_rows = [
["John", "1 Main Street"]
]
check_report
end
end
end
end
describe ".rules" do
describe "#group_by" do
before do
@columns = {
hub: proc { |item| item.hub },
customer: proc { |item| item.customer },
product: proc { |item| item.product },
quantity: proc { |item| item.quantity },
}
@query_result = [
OpenStruct.new(hub: "Hub 1", customer: "John", product: "Apple", quantity: 4),
OpenStruct.new(hub: "Hub 2", customer: "John", product: "Pear", quantity: 3),
OpenStruct.new(hub: "Hub 2", customer: "John", product: "Apple", quantity: 5),
OpenStruct.new(hub: "Hub 1", customer: "Abby", product: "Orange", quantity: 6),
]
end
it "works with symbol or proc" do
@rules = [
{ group_by: proc { |_i, row| row.hub }, fields_used_in_header: [:hub], header: true },
{ group_by: :customer, header: true }
]
allow(subject).to receive(:display_header_row?).and_return(true)
@expected_rows = [
{ header: "Hub 1" },
{ header: "Abby" },
{ product: "Orange", quantity: 6 },
{ header: "John" },
{ product: "Apple", quantity: 4 },
{ header: "Hub 2" },
{ header: "John" },
{ product: "Pear", quantity: 3 },
{ product: "Apple", quantity: 5 },
]
check_report
end
end
describe "#sort_by" do
before do
@columns = {
hub_name: proc { |item| item.hub[:name] }
}
hub1 = { name: "Hub 1", popularity: 5 }
hub2 = { name: "Hub 2", popularity: 2 }
@query_result = [
OpenStruct.new(hub: hub2),
OpenStruct.new(hub: hub1)
]
end
it "use default sort" do
@rules = [{
group_by: proc { |item, _row| item.hub }
}]
@expected_rows = [
{ hub_name: "Hub 1" },
{ hub_name: "Hub 2" },
]
check_report
end
it "use sort_by proc" do
@rules = [{
group_by: proc { |item, _row| item.hub },
sort_by: proc { |hub| hub[:popularity] }
}]
@expected_rows = [
{ hub_name: "Hub 2" },
{ hub_name: "Hub 1" }
]
check_report
end
end
describe "#summary_row" do
before do
@query_result = [
OpenStruct.new(hub: "Hub 1", customer: "John", product: "Apple", quantity: 4),
OpenStruct.new(hub: "Hub 2", customer: "John", product: "Pear", quantity: 3),
OpenStruct.new(hub: "Hub 2", customer: "John", product: "Apple", quantity: 5),
OpenStruct.new(hub: "Hub 1", customer: "Abby", product: "Orange", quantity: 6),
]
end
it "groups and sum" do
@columns = {
hub: proc { |item| item.hub },
quantity: proc { |item| item.quantity },
count: proc { |_item| "" },
}
@rules = [{
group_by: :hub,
summary_row: proc do |group_key, items, rows|
{ count: "#{group_key} count=#{items.count}", quantity: rows.sum(&:quantity) }
end,
summary_row_label: "TOTAL"
}]
@expetec_rows = [
{ hub: "Hub 1", quantity: 4, count: "" },
{ hub: "Hub 1", quantity: 6, count: "" },
{ hub: "TOTAL", quantity: 10, count: "Hub 1 count=2" },
{ hub: "Hub 2", quantity: 3, count: "" },
{ hub: "Hub 2", quantity: 5, count: "" },
{ hub: "TOTAL", quantity: 8, count: "Hub 2 count=2" }
]
check_report
end
end
describe "should not group when for JSON" do
before do
@query_result = [
OpenStruct.new(hub: "Hub 1", customer: "John", quantity: 4)
]
@columns = {
hub: proc { |item| item.hub },
customer: proc { |item| item.customer },
quantity: proc { |item| item.quantity },
}
@rules = [{
group_by: :hub,
header: true,
summary_row: proc do |_group_key, _items, rows|
{ quantity: rows.sum(&:quantity) }
end
}]
end
describe "for fields_to_show" do
let(:params) { { fields_to_show: [:hub, :quantity], report_format: 'json' } }
it "works" do
@expetec_rows = [
{ hub: "Hub 1", quantity: 4 }
]
check_report
end
end
describe "for fields_to_hide" do
let(:params) { { fields_to_hide: [:customer], report_format: 'json' } }
it "works" do
@expetec_rows = [
{ hub: "Hub 1", quantity: 4 }
]
check_report
end
end
end
end
end
end
# rubocop:enable Metrics/ModuleLength