# frozen_string_literal: true
RSpec.describe Blacklight::FacetsHelperBehavior do
let(:blacklight_config) { Blacklight::Configuration.new }
around { |test| Deprecation.silence(described_class) { test.call } }
before do
allow(helper).to receive(:blacklight_config).and_return blacklight_config
end
describe "has_facet_values?" do
let(:empty) { double(items: [], name: 'empty') }
let(:response) { instance_double(Blacklight::Solr::Response) }
it "is true if there are any facets to display" do
a = double(items: [1, 2], name: 'a')
b = double(items: %w[b c], name: 'b')
fields = [a, b, empty]
expect(helper.has_facet_values?(fields, response)).to be true
end
it "is false if all facets are empty" do
expect(helper.has_facet_values?([empty], response)).to be false
end
describe "different config" do
let(:blacklight_config) { Blacklight::Configuration.new { |config| config.add_facet_field 'basic_field', if: false } }
it "is false if no facets are displayable" do
a = double(items: [1, 2], name: 'basic_field')
expect(helper.has_facet_values?([a], response)).to be false
end
end
end
describe "should_render_facet?" do
let(:blacklight_config) do
Blacklight::Configuration.new do |config|
config.add_facet_field 'basic_field'
config.add_facet_field 'no_show', show: false
config.add_facet_field 'helper_show', show: :my_custom_check
config.add_facet_field 'helper_with_an_arg_show', show: :my_custom_check_with_an_arg
config.add_facet_field 'lambda_show', show: ->(_context, _config, _field) { true }
config.add_facet_field 'lambda_no_show', show: ->(_context, _config, _field) { false }
end
end
it "renders facets with items" do
a = double(items: [1, 2], name: 'basic_field')
expect(helper.should_render_facet?(a)).to be true
end
it "does not render facets without items" do
empty = double(items: [], name: 'basic_field')
expect(helper.should_render_facet?(empty)).to be false
end
it "does not render facets where show is set to false" do
a = double(items: [1, 2], name: 'no_show')
expect(helper.should_render_facet?(a)).to be false
end
it "calls a helper to determine if it should render a field" do
allow(controller).to receive_messages(my_custom_check: true)
a = double(items: [1, 2], name: 'helper_show')
expect(helper.should_render_facet?(a)).to be true
end
it "calls a helper to determine if it should render a field" do
a = double(items: [1, 2], name: 'helper_with_an_arg_show')
allow(controller).to receive(:my_custom_check_with_an_arg).with(blacklight_config.facet_fields['helper_with_an_arg_show'], a).and_return(true)
expect(helper.should_render_facet?(a)).to be true
end
it "evaluates a Proc to determine if it should render a field" do
a = double(items: [1, 2], name: 'lambda_show')
expect(helper.should_render_facet?(a)).to be true
a = double(items: [1, 2], name: 'lambda_no_show')
expect(helper.should_render_facet?(a)).to be false
end
end
describe "should_collapse_facet?" do
let(:blacklight_config) do
Blacklight::Configuration.new do |config|
config.add_facet_field 'basic_field'
config.add_facet_field 'no_collapse', collapse: false
end
end
it "is collapsed by default" do
expect(helper.should_collapse_facet?(blacklight_config.facet_fields['basic_field'])).to be true
end
it "does not be collapsed if the configuration says so" do
expect(helper.should_collapse_facet?(blacklight_config.facet_fields['no_collapse'])).to be false
end
it "does not be collapsed if it is in the params" do
params[:f] = ActiveSupport::HashWithIndifferentAccess.new(basic_field: [1], no_collapse: [2])
expect(helper.should_collapse_facet?(blacklight_config.facet_fields['basic_field'])).to be false
expect(helper.should_collapse_facet?(blacklight_config.facet_fields['no_collapse'])).to be false
end
end
describe "facet_by_field_name" do
around { |test| Deprecation.silence(Blacklight::Facet) { test.call } }
it "retrieves the facet from the response given a string" do
facet_config = double(query: nil, field: 'b', key: 'a')
facet_field = double
allow(helper).to receive(:facet_configuration_for_field).with('b').and_return(facet_config)
response = instance_double(Blacklight::Solr::Response, aggregations: { 'b' => facet_field })
expect(helper.facet_by_field_name('b', response)).to eq facet_field
end
end
describe "render_facet_partials" do
let(:a) { double(items: [1, 2]) }
let(:b) { double(items: %w[b c]) }
let(:response) { instance_double(Blacklight::Solr::Response) }
it "tries to render all provided facets" do
empty = double(items: [])
fields = [a, b, empty]
expect(helper).to receive(:render_facet_limit).with(a, {})
expect(helper).to receive(:render_facet_limit).with(b, {})
expect(helper).to receive(:render_facet_limit).with(empty, {})
helper.render_facet_partials fields, response: response
end
it "defaults to the configured facets" do
allow(Deprecation).to receive(:warn)
expect(helper).to receive(:facet_field_names) { [a, b] }
expect(helper).to receive(:render_facet_limit).with(a, {})
expect(helper).to receive(:render_facet_limit).with(b, {})
helper.render_facet_partials
end
end
describe "render_facet_limit" do
let(:blacklight_config) do
Blacklight::Configuration.new do |config|
config.add_facet_field 'basic_field'
config.add_facet_field 'component_field', component: true
config.add_facet_field 'non_rendering_component_field', component: true, if: false
config.add_facet_field 'pivot_facet_field', pivot: %w[a b]
config.add_facet_field 'my_pivot_facet_field_with_custom_partial', partial: 'custom_facet_partial', pivot: %w[a b]
config.add_facet_field 'my_facet_field_with_custom_partial', partial: 'custom_facet_partial'
end
end
let(:mock_custom_facet) { double(name: 'my_facet_field_with_custom_partial', items: [1, 2, 3]) }
it "sets basic local variables" do
mock_facet = double(name: 'basic_field', items: [1, 2, 3])
expect(helper).to receive(:render).with(hash_including(partial: 'facet_limit',
locals: {
field_name: 'basic_field',
facet_field: helper.blacklight_config.facet_fields['basic_field'],
display_facet: mock_facet
}))
helper.render_facet_limit(mock_facet)
end
it "renders a facet _not_ declared in the configuration" do
mock_facet = double(name: 'asdf', items: [1, 2, 3])
expect(helper).to receive(:render).with(hash_including(partial: 'facet_limit'))
helper.render_facet_limit(mock_facet)
end
it "gets the partial name from the configuration" do
expect(helper).to receive(:render).with(hash_including(partial: 'custom_facet_partial'))
helper.render_facet_limit(mock_custom_facet)
end
it "uses a partial layout for rendering the facet frame" do
expect(helper).to receive(:render).with(hash_including(layout: 'facet_layout'))
helper.render_facet_limit(mock_custom_facet)
end
it "allows the caller to opt-out of facet layouts" do
expect(helper).to receive(:render).with(hash_including(layout: nil))
helper.render_facet_limit(mock_custom_facet, layout: nil)
end
it "renders the facet_pivot partial for pivot facets" do
mock_facet = double(name: 'pivot_facet_field', items: [1, 2, 3])
expect(helper).to receive(:render).with(hash_including(partial: 'facet_pivot'))
helper.render_facet_limit(mock_facet)
end
it "lets you override the rendered partial for pivot facets" do
mock_facet = double(name: 'my_pivot_facet_field_with_custom_partial', items: [1, 2, 3])
expect(helper).to receive(:render).with(hash_including(partial: 'custom_facet_partial'))
helper.render_facet_limit(mock_facet)
end
it "lets you override the rendered partial for pivot facets" do
mock_facet = double(name: 'component_field')
expect(helper).to receive(:render).with(an_instance_of(Blacklight::FacetComponent))
helper.render_facet_limit(mock_facet)
end
it "lets you override the rendered partial for pivot facets" do
mock_facet = double(name: 'non_rendering_component_field')
expect(helper.render_facet_limit(mock_facet)).to be_blank
end
end
describe "render_facet_limit_list" do
subject { helper.render_facet_limit_list(paginator, 'type_solr_field') }
let(:f1) { Blacklight::Solr::Response::Facets::FacetItem.new(hits: '792', value: 'Book') }
let(:f2) { Blacklight::Solr::Response::Facets::FacetItem.new(hits: '65', value: 'Musical Score') }
let(:paginator) { Blacklight::Solr::FacetPaginator.new([f1, f2], limit: 10) }
before do
allow(helper).to receive(:search_action_path) do |*args|
search_catalog_path *args
end
end
it "draws a list of elements" do
expect(subject).to have_selector 'li', count: 2
expect(subject).to have_selector 'li:first-child a.facet-select', text: 'Book'
expect(subject).to have_selector 'li:nth-child(2) a.facet-select', text: 'Musical Score'
end
context "when one of the facet items is rendered as nil" do
# An app may override render_facet_item to filter out some undesired facet items by returning nil.
before do
allow(helper.method(:render_facet_item)).to receive(:owner).and_return(self.class)
# allow_any_instance_of(Blacklight::FacetItemComponent).to receive(:overridden_helper_methods?).and_return(true)
allow(helper).to receive(:render_facet_item).and_return('Book'.html_safe, nil)
end
around { |test| Deprecation.silence(Blacklight::FacetItemComponent) { test.call } }
it "draws a list of elements" do
expect(subject).to have_selector 'li', count: 1
expect(subject).to have_selector 'li:first-child a.facet-select', text: 'Book'
end
end
end
describe "facet_field_in_params?" do
before do
blacklight_config.add_facet_field "some-field"
end
it "checks if the facet field is selected in the user params" do
allow(helper).to receive_messages(params: { f: { "some-field" => ["x"] } })
expect(helper).to be_facet_field_in_params("some-field")
expect(helper.facet_field_in_params?("other-field")).not_to be true
end
end
describe "facet_params" do
let(:facet_config) { ["some-field"] }
let(:params) { { f: { "some-field" => ["x"] } } }
before do
blacklight_config.add_facet_field *facet_config
allow(helper).to receive_messages(params: params)
end
it "extracts the facet parameters for a field" do
expect(helper.facet_params("some-field")).to match_array ["x"]
end
context "a facet is not keyed by the field name" do
let(:facet_config) { ["some-key", { field: "some-field" }] }
let(:params) { { f: { "some-key" => ["x"] } } }
it "uses the blacklight key to extract the right fields" do
expect(helper.facet_params("some-key")).to match_array ["x"]
end
it "looks up facet params by configured field or key values" do
expect(helper.facet_params("some-field")).to match_array ["x"]
end
end
end
describe "facet_field_in_params?" do
let(:search_state) { double }
before do
allow(helper).to receive_messages(search_state: search_state)
end
it "checks if any value is selected for a given facet" do
allow(search_state).to receive(:has_facet?).with(having_attributes(key: 'some-facet')).and_return(true)
expect(helper.facet_field_in_params?("some-facet")).to eq true
end
it "is false if no value for facet is selected" do
allow(search_state).to receive(:has_facet?).with(having_attributes(key: 'some-facet')).and_return(false)
expect(helper.facet_field_in_params?("some-facet")).to eq false
end
end
describe "facet_in_params?" do
let(:search_state) { double }
before do
allow(helper).to receive_messages(search_state: search_state)
allow(search_state).to receive(:has_facet?).with(having_attributes(key: 'some-facet'), value: 'x').and_return(true)
allow(search_state).to receive(:has_facet?).with(having_attributes(key: 'some-facet'), value: 'y').and_return(false)
end
it "checks if a particular value is set in the facet params" do
expect(helper.facet_in_params?("some-facet", "x")).to eq true
expect(helper.facet_in_params?("some-facet", "y")).to eq false
end
end
describe "render_facet_value" do
let(:item) { double(value: 'A', hits: 10) }
let(:search_state) { double(has_facet?: false, add_facet_params_and_redirect: { controller: 'catalog' }) }
before do
allow(helper).to receive(:facet_configuration_for_field).with('simple_field').and_return(Blacklight::Configuration::FacetField.new(key: 'simple_field', query: nil, date: nil, helper_method: nil, single: false, url_method: nil, item_presenter: nil))
allow(helper).to receive(:facet_display_value).and_return('Z')
allow(helper).to receive(:search_state).and_return(search_state)
allow(helper).to receive(:search_action_path) do |*args|
search_catalog_path *args
end
end
describe "simple case" do
let(:expected_html) { 'Z10' }
it "uses facet_display_value" do
result = helper.render_facet_value('simple_field', item)
expect(result).to be_equivalent_to(expected_html).respecting_element_order
end
end
describe "when :url_method is set" do
let(:expected_html) { 'Z10' }
it "uses that method" do
allow(helper).to receive(:facet_configuration_for_field).with('simple_field').and_return(Blacklight::Configuration::FacetField.new(key: 'simple_field', query: nil, date: nil, helper_method: nil, single: false, url_method: :test_method, item_presenter: nil))
allow(helper).to receive(:test_method).with('simple_field', item).and_return('/blabla')
result = helper.render_facet_value('simple_field', item)
expect(result).to be_equivalent_to(expected_html).respecting_element_order
end
end
describe "when :suppress_link is set" do
let(:expected_html) { 'Z10' }
it "suppresses the link" do
result = helper.render_facet_value('simple_field', item, suppress_link: true)
expect(result).to be_equivalent_to(expected_html).respecting_element_order
end
end
end
describe "#facet_display_value" do
it "justs be the facet value for an ordinary facet" do
allow(helper).to receive(:facet_configuration_for_field).with('simple_field').and_return(double(query: nil, date: nil, helper_method: nil, url_method: nil, item_presenter: nil))
expect(helper.facet_display_value('simple_field', 'asdf')).to eq 'asdf'
end
it "allows you to pass in a :helper_method argument to the configuration" do
allow(helper).to receive(:facet_configuration_for_field).with('helper_field').and_return(double(query: nil, date: nil, url_method: nil, helper_method: :my_facet_value_renderer, item_presenter: nil))
allow(helper).to receive(:my_facet_value_renderer).with('qwerty').and_return('abc')
expect(helper.facet_display_value('helper_field', 'qwerty')).to eq 'abc'
end
it "extracts the configuration label for a query facet" do
allow(helper).to receive(:facet_configuration_for_field).with('query_facet').and_return(double(query: { 'query_key' => { label: 'XYZ' } }, date: nil, helper_method: nil, url_method: nil, item_presenter: nil))
expect(helper.facet_display_value('query_facet', 'query_key')).to eq 'XYZ'
end
it "localizes the label for date-type facets" do
allow(helper).to receive(:facet_configuration_for_field).with('date_facet').and_return(double('date' => true, :query => nil, :helper_method => nil, :url_method => nil, :item_presenter => nil))
expect(helper.facet_display_value('date_facet', '2012-01-01')).to eq 'Sun, 01 Jan 2012 00:00:00 +0000'
end
it "localizes the label for date-type facets with the supplied localization options" do
allow(helper).to receive(:facet_configuration_for_field).with('date_facet').and_return(double('date' => { format: :short }, :query => nil, :helper_method => nil, :url_method => nil, :item_presenter => nil))
expect(helper.facet_display_value('date_facet', '2012-01-01')).to eq '01 Jan 00:00'
end
end
describe "#facet_field_id" do
it "is the parameterized version of the facet field" do
expect(helper.facet_field_id(double(key: 'some field'))).to eq "facet-some-field"
end
end
describe '#facet_field_presenter' do
let(:facet_config) { Blacklight::Configuration::FacetField.new(key: 'x').normalize! }
let(:display_facet) { double }
it 'wraps the facet data in a presenter' do
presenter = helper.facet_field_presenter(facet_config, display_facet)
expect(presenter).to be_a_kind_of Blacklight::FacetFieldPresenter
expect(presenter.facet_field).to eq facet_config
expect(presenter.display_facet).to eq display_facet
expect(presenter.view_context).to eq helper
end
it 'uses the facet config to determine the presenter class' do
stub_const('SomePresenter', Class.new(Blacklight::FacetFieldPresenter))
facet_config.presenter = SomePresenter
presenter = helper.facet_field_presenter(facet_config, display_facet)
expect(presenter).to be_a_kind_of SomePresenter
end
end
end