blacklight 7.24.0 → 7.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +4 -4
  3. data/VERSION +1 -1
  4. data/app/assets/javascripts/blacklight/blacklight.js +2 -2
  5. data/app/components/blacklight/constraint_component.rb +1 -1
  6. data/app/components/blacklight/constraint_layout_component.rb +1 -1
  7. data/app/components/blacklight/constraints_component.rb +1 -1
  8. data/app/components/blacklight/document/action_component.rb +1 -1
  9. data/app/components/blacklight/document/actions_component.rb +1 -1
  10. data/app/components/blacklight/document/bookmark_component.rb +1 -1
  11. data/app/components/blacklight/document/citation_component.rb +2 -2
  12. data/app/components/blacklight/document/group_component.rb +3 -2
  13. data/app/components/blacklight/document/more_like_this_component.rb +1 -1
  14. data/app/components/blacklight/document/thumbnail_component.rb +1 -1
  15. data/app/components/blacklight/document_component.rb +1 -2
  16. data/app/components/blacklight/document_metadata_component.rb +1 -1
  17. data/app/components/blacklight/document_title_component.rb +1 -1
  18. data/app/components/blacklight/facet_field_checkboxes_component.rb +1 -1
  19. data/app/components/blacklight/facet_field_component.rb +1 -1
  20. data/app/components/blacklight/facet_field_filter_component.rb +1 -1
  21. data/app/components/blacklight/facet_field_inclusive_constraint_component.rb +1 -1
  22. data/app/components/blacklight/facet_field_list_component.rb +1 -1
  23. data/app/components/blacklight/facet_field_no_layout_component.rb +1 -1
  24. data/app/components/blacklight/facet_field_pagination_component.rb +1 -1
  25. data/app/components/blacklight/facet_item_component.rb +1 -1
  26. data/app/components/blacklight/facet_item_pivot_component.rb +1 -1
  27. data/app/components/blacklight/hidden_search_state_component.rb +2 -2
  28. data/app/components/blacklight/metadata_field_component.rb +1 -1
  29. data/app/components/blacklight/metadata_field_layout_component.rb +1 -1
  30. data/app/components/blacklight/response/facet_group_component.rb +1 -1
  31. data/app/components/blacklight/response/pagination_component.rb +1 -1
  32. data/app/components/blacklight/search_bar_component.html.erb +7 -7
  33. data/app/components/blacklight/search_bar_component.rb +18 -13
  34. data/app/components/blacklight/search_context_component.rb +1 -1
  35. data/app/components/blacklight/start_over_button_component.rb +1 -1
  36. data/app/helpers/blacklight/blacklight_helper_behavior.rb +3 -1
  37. data/app/helpers/blacklight/catalog_helper_behavior.rb +1 -1
  38. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +5 -7
  39. data/app/javascript/blacklight/modal.js +2 -2
  40. data/app/presenters/blacklight/search_bar_presenter.rb +2 -0
  41. data/app/services/blacklight/field_retriever.rb +1 -1
  42. data/app/views/catalog/_constraints.html.erb +2 -2
  43. data/app/views/catalog/_facet_group.html.erb +1 -1
  44. data/app/views/catalog/_search_form.html.erb +2 -2
  45. data/app/views/shared/_header_navbar.html.erb +5 -1
  46. data/lib/blacklight/component.rb +40 -0
  47. data/lib/blacklight/configuration/facet_field.rb +1 -1
  48. data/lib/blacklight/configuration/fields.rb +10 -11
  49. data/lib/blacklight/configuration/view_config.rb +6 -0
  50. data/lib/blacklight/configuration.rb +320 -179
  51. data/lib/blacklight/deprecations/search_state_normalization.rb +52 -0
  52. data/lib/blacklight/search_state/filter_field.rb +44 -16
  53. data/lib/blacklight/search_state.rb +55 -31
  54. data/lib/blacklight/solr/search_builder_behavior.rb +3 -1
  55. data/lib/blacklight.rb +1 -0
  56. data/package.json +1 -1
  57. data/spec/components/blacklight/constraints_component_spec.rb +14 -1
  58. data/spec/components/blacklight/facet_field_list_component_spec.rb +6 -1
  59. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +7 -1
  60. data/spec/controllers/blacklight/base_spec.rb +4 -1
  61. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +23 -6
  62. data/spec/helpers/blacklight/url_helper_behavior_spec.rb +7 -0
  63. data/spec/lib/blacklight/component_spec.rb +43 -0
  64. data/spec/lib/blacklight/search_state/filter_field_spec.rb +12 -1
  65. data/spec/lib/blacklight/search_state_spec.rb +17 -3
  66. data/spec/models/blacklight/configuration_spec.rb +2 -2
  67. data/spec/models/blacklight/solr/search_builder_spec.rb +15 -0
  68. data/spec/presenters/blacklight/facet_field_presenter_spec.rb +10 -4
  69. data/spec/presenters/blacklight/facet_grouped_item_presenter_spec.rb +6 -1
  70. data/spec/presenters/blacklight/field_presenter_spec.rb +2 -0
  71. data/spec/views/catalog/index.json.jbuilder_spec.rb +1 -0
  72. metadata +7 -3
@@ -6,12 +6,22 @@ module Blacklight
6
6
  class FilterField
7
7
  MISSING = { missing: true }.freeze
8
8
 
9
- # @param [Blacklight::Configuration::FacetField] config
9
+ # @!attribute config
10
+ # @return [Blacklight::Configuration::FacetField]
10
11
  attr_reader :config
11
12
 
12
- # @param [Blacklight::SearchState] search_state
13
+ # @!attribute search_state
14
+ # @return [Blacklight::SearchState]
13
15
  attr_reader :search_state
14
16
 
17
+ # @!attribute param
18
+ # @return [String,Symbol]
19
+ attr_reader :filters_key
20
+
21
+ # @!attribute inclusive_param
22
+ # @return [String,Symbol]
23
+ attr_reader :inclusive_filters_key
24
+
15
25
  # @return [String,Symbol]
16
26
  delegate :key, to: :config
17
27
 
@@ -20,9 +30,11 @@ module Blacklight
20
30
  def initialize(config, search_state)
21
31
  @config = config
22
32
  @search_state = search_state
33
+ @filters_key = :f
34
+ @inclusive_filters_key = :f_inclusive
23
35
  end
24
36
 
25
- # @param [String,#value] a filter item to add to the url
37
+ # @param [String,#value] item a filter item to add to the url
26
38
  # @return [Blacklight::SearchState] new state
27
39
  def add(item)
28
40
  new_state = search_state.reset_search
@@ -41,7 +53,7 @@ module Blacklight
41
53
 
42
54
  url_key = key
43
55
  params = new_state.params
44
- param = :f
56
+ param = filters_key
45
57
  value = as_url_parameter(item)
46
58
 
47
59
  if value == Blacklight::SearchState::FilterField::MISSING
@@ -49,7 +61,7 @@ module Blacklight
49
61
  value = Blacklight::Engine.config.blacklight.facet_missing_param
50
62
  end
51
63
 
52
- param = :f_inclusive if value.is_a?(Array)
64
+ param = inclusive_filters_key if value.is_a?(Array)
53
65
 
54
66
  # value could be a string
55
67
  params[param] = (params[param] || {}).dup
@@ -66,7 +78,7 @@ module Blacklight
66
78
  new_state.reset(params)
67
79
  end
68
80
 
69
- # @param [String,#value] a filter to remove from the url
81
+ # @param [String,#value] item a filter to remove from the url
70
82
  # @return [Blacklight::SearchState] new state
71
83
  def remove(item)
72
84
  new_state = search_state.reset_search
@@ -77,7 +89,7 @@ module Blacklight
77
89
  url_key = config.key
78
90
  params = new_state.params
79
91
 
80
- param = :f
92
+ param = filters_key
81
93
  value = as_url_parameter(item)
82
94
 
83
95
  if value == Blacklight::SearchState::FilterField::MISSING
@@ -85,7 +97,7 @@ module Blacklight
85
97
  value = Blacklight::Engine.config.blacklight.facet_missing_param
86
98
  end
87
99
 
88
- param = :f_inclusive if value.is_a?(Array)
100
+ param = inclusive_filters_key if value.is_a?(Array)
89
101
 
90
102
  # need to dup the facet values too,
91
103
  # if the values aren't dup'd, then the values
@@ -110,17 +122,25 @@ module Blacklight
110
122
  end
111
123
 
112
124
  # @return [Array] an array of applied filters
113
- def values
125
+ def values(except: [])
114
126
  params = search_state.params
115
- f = Array(params.dig(:f, key))
116
- f_inclusive = [params.dig(:f_inclusive, key)] if params.dig(:f_inclusive, key).present?
117
- f_missing = [Blacklight::SearchState::FilterField::MISSING] if params.dig(:f, "-#{key}")&.any? { |v| v == Blacklight::Engine.config.blacklight.facet_missing_param }
127
+ return [] if params.blank?
128
+
129
+ f = except.include?(:filters) ? [] : [params.dig(filters_key, key)].flatten.compact
130
+ f_inclusive = [params.dig(:f_inclusive, key)] unless params.dig(inclusive_filters_key, key).blank? || except.include?(:inclusive_filters)
131
+ f_missing = [Blacklight::SearchState::FilterField::MISSING] if params.dig(filters_key, "-#{key}")&.any? { |v| v == Blacklight::Engine.config.blacklight.facet_missing_param }
132
+ f_missing = [] if except.include?(:missing)
118
133
 
119
134
  f + (f_inclusive || []) + (f_missing || [])
120
135
  end
121
136
  delegate :any?, to: :values
122
137
 
123
- # @param [String,#value] a filter to remove from the url
138
+ # Appease rubocop rules by implementing #each_value
139
+ def each_value(except: [], &block)
140
+ values(except: except).each(&block)
141
+ end
142
+
143
+ # @param [String,#value] item a filter to remove from the url
124
144
  # @return [Boolean] whether the provided filter is currently applied/selected
125
145
  def include?(item)
126
146
  if item.respond_to?(:field) && item.field != key
@@ -131,14 +151,22 @@ module Blacklight
131
151
  params = search_state.params
132
152
 
133
153
  if value.is_a?(Array)
134
- (params.dig(:f_inclusive, key) || []).to_set == value.to_set
154
+ (params.dig(inclusive_filters_key, key) || []).to_set == value.to_set
135
155
  elsif value == Blacklight::SearchState::FilterField::MISSING
136
- (params.dig(:f, "-#{key}") || []).include?(Blacklight::Engine.config.blacklight.facet_missing_param)
156
+ (params.dig(filters_key, "-#{key}") || []).include?(Blacklight::Engine.config.blacklight.facet_missing_param)
137
157
  else
138
- (params.dig(:f, key) || []).include?(value)
158
+ (params.dig(filters_key, key) || []).include?(value)
139
159
  end
140
160
  end
141
161
 
162
+ def needs_normalization?(value_params)
163
+ value_params&.is_a?(Hash) && value_params != Blacklight::SearchState::FilterField::MISSING
164
+ end
165
+
166
+ def normalize(value_params)
167
+ needs_normalization?(value_params) ? value_params.values : value_params
168
+ end
169
+
142
170
  private
143
171
 
144
172
  # TODO: this code is duplicated in Blacklight::FacetsHelperBehavior
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'blacklight/deprecations/search_state_normalization'
3
4
  require 'blacklight/search_state/filter_field'
4
5
 
5
6
  module Blacklight
@@ -7,6 +8,7 @@ module Blacklight
7
8
  # parameters namely: :f, :q, :page, :per_page and, :sort
8
9
  class SearchState
9
10
  extend Deprecation
11
+ include Blacklight::Deprecations::SearchStateNormalization
10
12
 
11
13
  attr_reader :blacklight_config # Must be called blacklight_config, because Blacklight::Facet calls blacklight_config.
12
14
  attr_reader :params
@@ -17,18 +19,7 @@ module Blacklight
17
19
 
18
20
  delegate :facet_configuration_for_field, to: :blacklight_config
19
21
 
20
- # @param [ActionController::Parameters] params
21
- # @param [Blacklight::Config] blacklight_config
22
- # @param [ApplicationController] controller used for the routing helpers
23
- def initialize(params, blacklight_config, controller = nil)
24
- @params = self.class.normalize_params(params)
25
- @blacklight_config = blacklight_config
26
- @controller = controller
27
- end
28
-
29
- def self.normalize_params(untrusted_params = {})
30
- params = untrusted_params
31
-
22
+ def self.modifiable_params(params)
32
23
  if params.respond_to?(:to_unsafe_h)
33
24
  # This is the typical (not-ActionView::TestCase) code path.
34
25
  params = params.to_unsafe_h
@@ -40,12 +31,55 @@ module Blacklight
40
31
  else
41
32
  params = params.dup.to_h.with_indifferent_access
42
33
  end
34
+ params
35
+ end
43
36
 
44
- # Normalize facet parameters mangled by facebook
45
- params[:f] = normalize_facet_params(params[:f]) if facet_params_need_normalization(params[:f])
46
- params[:f_inclusive] = normalize_facet_params(params[:f_inclusive]) if facet_params_need_normalization(params[:f_inclusive])
37
+ # @param [ActionController::Parameters] params
38
+ # @param [Blacklight::Config] blacklight_config
39
+ # @param [ApplicationController] controller used for the routing helpers
40
+ def initialize(params, blacklight_config, controller = nil)
41
+ @blacklight_config = blacklight_config
42
+ @controller = controller
43
+ @params = SearchState.modifiable_params(params)
44
+ normalize_params! if needs_normalization?
45
+ end
47
46
 
48
- params
47
+ def needs_normalization?
48
+ return false if params.blank?
49
+ return true if (params.keys.map(&:to_s) - permitted_fields.map(&:to_s)).present?
50
+
51
+ !!filters.detect { |filter| filter.values.detect { |value| filter.needs_normalization?(value) } }
52
+ end
53
+
54
+ def normalize_params!
55
+ @params = normalize_params
56
+ end
57
+
58
+ def normalize_params
59
+ return params unless needs_normalization?
60
+
61
+ base_params = params.slice(*blacklight_config.search_state_fields)
62
+ normal_state = blacklight_config.facet_fields.each_value.inject(reset(base_params)) do |working_state, filter_key|
63
+ f = filter(filter_key)
64
+ next working_state unless f.any?
65
+
66
+ filter_values = f.values(except: [:inclusive_filters]).inject([]) do |memo, filter_value|
67
+ # flatten arrays that had been mangled into integer-indexed hashes
68
+ memo.concat([f.normalize(filter_value)].flatten)
69
+ end
70
+ filter_values = f.values(except: [:filters, :missing]).inject(filter_values) do |memo, filter_value|
71
+ memo << f.normalize(filter_value)
72
+ end
73
+ filter_values.inject(working_state) do |memo, filter_value|
74
+ memo.filter(filter_key).add(filter_value)
75
+ end
76
+ end
77
+ normal_state.params
78
+ end
79
+
80
+ def permitted_fields
81
+ filter_keys = filter_fields.inject(Set.new) { |memo, filter| memo.merge [filter.filters_key, filter.inclusive_filters_key] }
82
+ blacklight_config.search_state_fields + filter_keys.subtract([nil, '']).to_a
49
83
  end
50
84
 
51
85
  def to_hash
@@ -129,11 +163,7 @@ module Blacklight
129
163
  end
130
164
 
131
165
  def filters
132
- @filters ||= blacklight_config.facet_fields.each_value.map do |value|
133
- f = filter(value)
134
-
135
- f if f.any?
136
- end.compact
166
+ @filters ||= filter_fields.select(&:any?)
137
167
  end
138
168
 
139
169
  def filter(field_key_or_field)
@@ -248,16 +278,6 @@ module Blacklight
248
278
  params[facet_request_keys[:prefix]]
249
279
  end
250
280
 
251
- def self.facet_params_need_normalization(facet_params)
252
- facet_params.is_a?(Hash) && facet_params.values.any? { |x| x.is_a?(Hash) }
253
- end
254
-
255
- def self.normalize_facet_params(facet_params)
256
- facet_params.transform_values do |value|
257
- value.is_a?(Hash) ? value.values : value
258
- end
259
- end
260
-
261
281
  private
262
282
 
263
283
  def search_field_key
@@ -279,5 +299,9 @@ module Blacklight
279
299
  def reset_search_params
280
300
  Parameters.sanitize(params).except(:page, :counter)
281
301
  end
302
+
303
+ def filter_fields
304
+ blacklight_config.facet_fields.each_value.map { |value| filter(value) }
305
+ end
282
306
  end
283
307
  end
@@ -146,7 +146,9 @@ module Blacklight::Solr
146
146
  if filter.config.filter_query_builder
147
147
  filter_query, subqueries = filter.config.filter_query_builder.call(self, filter, solr_parameters)
148
148
 
149
- solr_parameters.append_filter_query(filter_query) if filter_query
149
+ Array(filter_query).each do |fq|
150
+ solr_parameters.append_filter_query(fq)
151
+ end
150
152
  solr_parameters.merge!(subqueries) if subqueries
151
153
  else
152
154
  filter.values.reject(&:blank?).each do |value|
data/lib/blacklight.rb CHANGED
@@ -7,6 +7,7 @@ require 'jbuilder'
7
7
 
8
8
  module Blacklight
9
9
  autoload :AbstractRepository, 'blacklight/abstract_repository'
10
+ autoload :Component, 'blacklight/component'
10
11
  autoload :Configuration, 'blacklight/configuration'
11
12
  autoload :Exceptions, 'blacklight/exceptions'
12
13
  autoload :Parameters, 'blacklight/parameters'
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blacklight-frontend",
3
- "version": "7.22.1",
3
+ "version": "7.25.0",
4
4
  "description": "[![Build Status](https://travis-ci.com/projectblacklight/blacklight.png?branch=main)](https://travis-ci.com/projectblacklight/blacklight) [![Gem Version](https://badge.fury.io/rb/blacklight.png)](http://badge.fury.io/rb/blacklight) [![Coverage Status](https://coveralls.io/repos/github/projectblacklight/blacklight/badge.svg?branch=main)](https://coveralls.io/github/projectblacklight/blacklight?branch=main)",
5
5
  "main": "app/assets/javascripts/blacklight",
6
6
  "scripts": {
@@ -12,7 +12,7 @@ RSpec.describe Blacklight::ConstraintsComponent, type: :component do
12
12
  end
13
13
 
14
14
  let(:blacklight_config) do
15
- Blacklight::Configuration.new.tap do |config|
15
+ Blacklight::Configuration.new.configure do |config|
16
16
  config.add_facet_field 'some_facet'
17
17
  end
18
18
  end
@@ -43,6 +43,19 @@ RSpec.describe Blacklight::ConstraintsComponent, type: :component do
43
43
  context 'with a facet' do
44
44
  let(:query_params) { { f: { some_facet: ['some value'] } } }
45
45
 
46
+ before do
47
+ controller.blacklight_config.configure do |config|
48
+ config.add_facet_field :some_facet
49
+ end
50
+ end
51
+
52
+ # this has to be cleaned up to prevent leaking class configuration
53
+ after do
54
+ controller.blacklight_config.configure do |config|
55
+ config['facet_fields'].delete('some_facet')
56
+ end
57
+ end
58
+
46
59
  it 'renders the query' do
47
60
  expect(rendered).to have_selector('.constraint-value > .filter-name', text: 'Some Facet').and(have_selector('.constraint-value > .filter-value', text: 'some value'))
48
61
  end
@@ -123,7 +123,12 @@ RSpec.describe Blacklight::FacetFieldListComponent, type: :component do
123
123
  )
124
124
  end
125
125
 
126
- let(:search_state) { Blacklight::SearchState.new(params.with_indifferent_access, Blacklight::Configuration.new) }
126
+ let(:blacklight_config) do
127
+ Blacklight::Configuration.new.configure do |config|
128
+ config.add_facet_field :field
129
+ end
130
+ end
131
+ let(:search_state) { Blacklight::SearchState.new(params.with_indifferent_access, blacklight_config) }
127
132
  let(:params) { { f_inclusive: { field: %w[a b c] } } }
128
133
 
129
134
  it 'displays the constraint above the list' do
@@ -7,8 +7,14 @@ RSpec.describe Blacklight::FacetItemPivotComponent, type: :component do
7
7
  render_inline_to_capybara_node(described_class.new(facet_item: facet_item))
8
8
  end
9
9
 
10
+ let(:blacklight_config) do
11
+ Blacklight::Configuration.new.configure do |config|
12
+ config.add_facet_field :z
13
+ end
14
+ end
15
+
10
16
  let(:search_state) do
11
- Blacklight::SearchState.new({}, Blacklight::Configuration.new)
17
+ Blacklight::SearchState.new({}, blacklight_config)
12
18
  end
13
19
 
14
20
  let(:facet_item) do
@@ -11,7 +11,10 @@ RSpec.describe Blacklight::Base do
11
11
  let(:raw_params) { HashWithIndifferentAccess.new a: 1 }
12
12
  let(:params) { ActionController::Parameters.new raw_params }
13
13
 
14
- before { allow(controller).to receive_messages(params: params) }
14
+ before do
15
+ controller.blacklight_config.search_state_fields << :a
16
+ allow(controller).to receive_messages(params: params)
17
+ end
15
18
 
16
19
  it "creates a path object" do
17
20
  expect(subject).to be_kind_of Blacklight::SearchState
@@ -246,6 +246,10 @@ RSpec.describe Blacklight::FacetsHelperBehavior do
246
246
  end
247
247
 
248
248
  describe "facet_field_in_params?" do
249
+ before do
250
+ blacklight_config.add_facet_field "some-field"
251
+ end
252
+
249
253
  it "checks if the facet field is selected in the user params" do
250
254
  allow(helper).to receive_messages(params: { f: { "some-field" => ["x"] } })
251
255
  expect(helper).to be_facet_field_in_params("some-field")
@@ -254,16 +258,29 @@ RSpec.describe Blacklight::FacetsHelperBehavior do
254
258
  end
255
259
 
256
260
  describe "facet_params" do
261
+ let(:facet_config) { ["some-field"] }
262
+ let(:params) { { f: { "some-field" => ["x"] } } }
263
+
264
+ before do
265
+ blacklight_config.add_facet_field *facet_config
266
+ allow(helper).to receive_messages(params: params)
267
+ end
268
+
257
269
  it "extracts the facet parameters for a field" do
258
- allow(helper).to receive_messages(params: { f: { "some-field" => ["x"] } })
259
270
  expect(helper.facet_params("some-field")).to match_array ["x"]
260
271
  end
261
272
 
262
- it "uses the blacklight key to extract the right fields" do
263
- blacklight_config.add_facet_field "some-key", field: "some-field"
264
- allow(helper).to receive_messages(params: { f: { "some-key" => ["x"] } })
265
- expect(helper.facet_params("some-key")).to match_array ["x"]
266
- expect(helper.facet_params("some-field")).to match_array ["x"]
273
+ context "a facet is not keyed by the field name" do
274
+ let(:facet_config) { ["some-key", { field: "some-field" }] }
275
+ let(:params) { { f: { "some-key" => ["x"] } } }
276
+
277
+ it "uses the blacklight key to extract the right fields" do
278
+ expect(helper.facet_params("some-key")).to match_array ["x"]
279
+ end
280
+
281
+ it "looks up facet params by configured field or key values" do
282
+ expect(helper.facet_params("some-field")).to match_array ["x"]
283
+ end
267
284
  end
268
285
  end
269
286
 
@@ -75,6 +75,13 @@ RSpec.describe Blacklight::UrlHelperBehavior do
75
75
  let(:query_params) { { q: "query", f: "facets", controller: 'catalog' } }
76
76
  let(:bookmarks_query_params) { { controller: 'bookmarks' } }
77
77
 
78
+ before do
79
+ # this is bad data but the legacy test exercises search fields, not filters
80
+ blacklight_config.configure do |config|
81
+ config.search_state_fields << :f
82
+ end
83
+ end
84
+
78
85
  it "builds a link tag to catalog using session[:search] for query params" do
79
86
  allow(helper).to receive(:current_search_session).and_return double(query_params: query_params)
80
87
  tag = helper.link_back_to_catalog
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Blacklight::Component do
4
+ let(:component_class) { Blacklight::DocumentTitleComponent }
5
+
6
+ context "subclassed" do
7
+ it "returns our Compiler implementation" do
8
+ expect(component_class.ancestors).to include described_class
9
+ expect(component_class.compiler).to be_a Blacklight::Component::EngineCompiler
10
+ end
11
+ end
12
+
13
+ describe Blacklight::Component::EngineCompiler do
14
+ subject(:compiler) { described_class.new(component_class) }
15
+
16
+ let(:original_compiler) { ViewComponent::Compiler.new(component_class) }
17
+ let(:original_path) { original_compiler.send(:templates).first[:path] }
18
+ let(:resolved_path) { compiler.templates.first[:path] }
19
+
20
+ context "without overrides" do
21
+ it "links to engine template" do
22
+ expect(resolved_path).not_to include(".internal_test_app")
23
+ expect(resolved_path).to eql(original_path)
24
+ end
25
+ end
26
+
27
+ context "with overrides" do
28
+ let(:path_match) do
29
+ Regexp.new(Regexp.escape(File.join(".internal_test_app", component_class.view_component_path)))
30
+ end
31
+
32
+ before do
33
+ allow(File).to receive(:exist?).and_call_original
34
+ allow(File).to receive(:exist?).with(path_match).and_return(true)
35
+ end
36
+
37
+ it "links to application template" do
38
+ expect(resolved_path).to include(".internal_test_app")
39
+ expect(resolved_path).not_to eql(original_path)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -6,10 +6,13 @@ RSpec.describe Blacklight::SearchState::FilterField do
6
6
  let(:params) { { f: { some_field: %w[1 2], another_field: ['3'] } } }
7
7
  let(:blacklight_config) do
8
8
  Blacklight::Configuration.new.configure do |config|
9
- config.add_facet_field 'some_field'
10
9
  config.add_facet_field 'another_field', single: true
10
+ simple_facet_fields.each { |simple_facet_field| config.add_facet_field simple_facet_field }
11
+ config.search_state_fields = config.search_state_fields + additional_search_fields
11
12
  end
12
13
  end
14
+ let(:simple_facet_fields) { [:some_field] }
15
+ let(:additional_search_fields) { [] }
13
16
  let(:controller) { double }
14
17
 
15
18
  describe '#add' do
@@ -50,6 +53,8 @@ RSpec.describe Blacklight::SearchState::FilterField do
50
53
  end
51
54
 
52
55
  context 'with a pivot facet-type item' do
56
+ let(:simple_facet_fields) { [:some_field, :some_other_field] }
57
+
53
58
  it 'includes the pivot facet fqs' do
54
59
  filter = search_state.filter('some_field')
55
60
  new_state = filter.add(OpenStruct.new(fq: { some_other_field: '5' }, value: '4'))
@@ -200,4 +205,10 @@ RSpec.describe Blacklight::SearchState::FilterField do
200
205
  expect(search_state.filter('some_field').include?(OpenStruct.new(value: '1'))).to eq true
201
206
  end
202
207
  end
208
+
209
+ describe '#needs_normalization?' do
210
+ it 'returns false for Blacklight::SearchState::FilterField::MISSING' do
211
+ expect(search_state.filter('some_field').needs_normalization?(Blacklight::SearchState::FilterField::MISSING)).to be false
212
+ end
213
+ end
203
214
  end
@@ -9,14 +9,19 @@ RSpec.describe Blacklight::SearchState do
9
9
  Blacklight::Configuration.new.configure do |config|
10
10
  config.index.title_field = 'title_tsim'
11
11
  config.index.display_type_field = 'format'
12
+ simple_facet_fields.each { |simple_facet_field| config.add_facet_field simple_facet_field }
13
+ config.search_state_fields = config.search_state_fields + additional_search_fields
12
14
  end
13
15
  end
14
16
 
15
17
  let(:parameter_class) { ActionController::Parameters }
16
18
  let(:controller) { double }
17
19
  let(:params) { parameter_class.new }
20
+ let(:simple_facet_fields) { [:facet_field_1, :facet_field_2] }
21
+ let(:additional_search_fields) { [] }
18
22
 
19
23
  describe '#to_h' do
24
+ let(:additional_search_fields) { [:a] }
20
25
  let(:data) { { a: '1' } }
21
26
  let(:params) { parameter_class.new data }
22
27
 
@@ -50,6 +55,7 @@ RSpec.describe Blacklight::SearchState do
50
55
  end
51
56
 
52
57
  context 'with facebooks badly mangled query parameters' do
58
+ let(:simple_facet_fields) { [:field] }
53
59
  let(:params) do
54
60
  { f: { field: { '0': 'first', '1': 'second' } },
55
61
  f_inclusive: { field: { '0': 'first', '1': 'second' } } }
@@ -62,6 +68,7 @@ RSpec.describe Blacklight::SearchState do
62
68
  end
63
69
 
64
70
  context 'deleting item from to_h' do
71
+ let(:additional_search_fields) { [:q_1] }
65
72
  let(:params) { { q: 'foo', q_1: 'bar' } }
66
73
 
67
74
  it 'does not mutate search_state to mutate search_state.to_h' do
@@ -74,6 +81,7 @@ RSpec.describe Blacklight::SearchState do
74
81
  end
75
82
 
76
83
  context 'deleting deep item from to_h' do
84
+ let(:additional_search_fields) { [:foo] }
77
85
  let(:params) { { foo: { bar: [] } } }
78
86
 
79
87
  it 'does not mutate search_state to deep mutate search_state.to_h' do
@@ -87,6 +95,7 @@ RSpec.describe Blacklight::SearchState do
87
95
  end
88
96
 
89
97
  describe 'interface compatibility with params' do
98
+ let(:simple_facet_fields) { [:ff] }
90
99
  let(:params) { parameter_class.new f: { ff: ['xyz'] } }
91
100
 
92
101
  it 'implements param methods' do
@@ -107,6 +116,7 @@ RSpec.describe Blacklight::SearchState do
107
116
  end
108
117
 
109
118
  describe '#filter_params' do
119
+ let(:simple_facet_fields) { [:ff] }
110
120
  let(:params) { parameter_class.new f: { ff: ['xyz'] } }
111
121
 
112
122
  it 'returns the query param' do
@@ -128,6 +138,7 @@ RSpec.describe Blacklight::SearchState do
128
138
  end
129
139
 
130
140
  context 'with a facet param' do
141
+ let(:simple_facet_fields) { [:ff] }
131
142
  let(:params) { parameter_class.new f: { ff: ['xyz'] } }
132
143
 
133
144
  it 'is true' do
@@ -137,6 +148,7 @@ RSpec.describe Blacklight::SearchState do
137
148
  end
138
149
 
139
150
  describe "params_for_search" do
151
+ let(:additional_search_fields) { [:default] }
140
152
  let(:params) { parameter_class.new 'default' => 'params' }
141
153
 
142
154
  it "takes original params" do
@@ -198,6 +210,7 @@ RSpec.describe Blacklight::SearchState do
198
210
  end
199
211
 
200
212
  context "with a block" do
213
+ let(:additional_search_fields) { [:a, :b, :c, :d] }
201
214
  let(:params) { parameter_class.new a: 1, b: 2 }
202
215
 
203
216
  it "evalutes the block and allow it to add or remove keys" do
@@ -356,6 +369,7 @@ RSpec.describe Blacklight::SearchState do
356
369
  end
357
370
 
358
371
  describe "#remove_facet_params" do
372
+ let(:simple_facet_fields) { [:some_field, :another_field] }
359
373
  let(:params) { parameter_class.new 'f' => facet_params }
360
374
  let(:facet_params) { {} }
361
375
 
@@ -382,9 +396,7 @@ RSpec.describe Blacklight::SearchState do
382
396
 
383
397
  context "when the facet has configuration" do
384
398
  before do
385
- allow(search_state).to receive(:facet_configuration_for_field).with('some_field').and_return(
386
- double(single: true, field: "a_solr_field", key: "some_key")
387
- )
399
+ blacklight_config.facet_fields['some_field'].merge!(single: true, field: "a_solr_field", key: 'some_key')
388
400
  end
389
401
 
390
402
  let(:facet_params) { { 'some_key' => %w[some_value another_value] } }
@@ -415,6 +427,8 @@ RSpec.describe Blacklight::SearchState do
415
427
  end
416
428
 
417
429
  describe '#reset' do
430
+ let(:additional_search_fields) { [:a] }
431
+
418
432
  it 'returns a search state with the given parameters' do
419
433
  new_state = search_state.reset('a' => 1)
420
434
 
@@ -552,7 +552,7 @@ RSpec.describe "Blacklight::Configuration", api: true do
552
552
  end
553
553
 
554
554
  it "takes ShowField argument" do
555
- config.add_sms_field("title_tsim", Blacklight::Configuration::SmsField.new(field: "title_display", label: "Title"))
555
+ config.add_sms_field("title_tsim", Blacklight::Configuration::DisplayField.new(field: "title_display", label: "Title"))
556
556
 
557
557
  expect(config.sms_fields["title_tsim"]).not_to be_nil
558
558
  expect(config.sms_fields["title_tsim"].label).to eq "Title"
@@ -598,7 +598,7 @@ RSpec.describe "Blacklight::Configuration", api: true do
598
598
  end
599
599
 
600
600
  it "takes ShowField argument" do
601
- config.add_email_field("title_tsim", Blacklight::Configuration::EmailField.new(field: "title_display", label: "Title"))
601
+ config.add_email_field("title_tsim", Blacklight::Configuration::DisplayField.new(field: "title_display", label: "Title"))
602
602
 
603
603
  expect(config.email_fields["title_tsim"]).not_to be_nil
604
604
  expect(config.email_fields["title_tsim"].label).to eq "Title"
@@ -273,6 +273,21 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, api: true do
273
273
  end
274
274
  end
275
275
 
276
+ context 'with a facet with a custom filter query builder that returns multiple values' do
277
+ let(:user_params) { { f: { some: ['value'] } }.with_indifferent_access }
278
+
279
+ before do
280
+ blacklight_config.add_facet_field 'some', filter_query_builder: (lambda do |*_args|
281
+ [['some:filter', 'another:filter'], { qq1: 'abc' }]
282
+ end)
283
+ end
284
+
285
+ it "has proper solr parameters" do
286
+ expect(subject[:fq]).to include('some:filter', 'another:filter')
287
+ expect(subject[:qq1]).to include('abc')
288
+ end
289
+ end
290
+
276
291
  describe 'with a json facet' do
277
292
  let(:user_params) { { f: { json_facet: ['value'] } }.with_indifferent_access }
278
293