blacklight 9.0.0.beta1 → 9.0.0.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. data/.github/matrix.json +47 -0
  3. data/.github/workflows/build.yml +16 -0
  4. data/.github/workflows/lint.yml +25 -0
  5. data/.github/workflows/main.yml +22 -0
  6. data/.github/workflows/release_7_x_scheduled.yml +39 -0
  7. data/.github/workflows/release_8_x_scheduled.yml +39 -0
  8. data/.github/workflows/test.yml +53 -0
  9. data/.rubocop.yml +70 -2
  10. data/.rubocop_todo.yml +43 -67
  11. data/.solr_wrapper.yml +2 -0
  12. data/VERSION +1 -1
  13. data/app/assets/builds/blacklight.css +19 -15
  14. data/app/assets/javascripts/blacklight/blacklight.esm.js +31 -69
  15. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  16. data/app/assets/javascripts/blacklight/blacklight.js +31 -69
  17. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  18. data/app/assets/stylesheets/blacklight/_bootstrap_overrides.scss +4 -0
  19. data/app/assets/stylesheets/blacklight/_facets.scss +2 -2
  20. data/app/assets/stylesheets/blacklight/_header.scss +4 -0
  21. data/app/assets/stylesheets/blacklight/_modal.scss +9 -8
  22. data/app/assets/stylesheets/blacklight/_pagination.scss +1 -3
  23. data/app/assets/stylesheets/blacklight/_search_history.scss +0 -4
  24. data/app/assets/stylesheets/blacklight/blacklight_defaults.scss +3 -0
  25. data/app/components/blacklight/advanced_search_form_component.rb +2 -2
  26. data/app/components/blacklight/constraints_component.rb +2 -2
  27. data/app/components/blacklight/document/action_component.rb +1 -3
  28. data/app/components/blacklight/document/bookmark_component.rb +2 -2
  29. data/app/components/blacklight/document/more_like_this_component.rb +2 -2
  30. data/app/components/blacklight/document/page_header_component.rb +2 -2
  31. data/app/components/blacklight/document/thumbnail_component.html.erb +3 -7
  32. data/app/components/blacklight/document/thumbnail_component.rb +7 -6
  33. data/app/components/blacklight/document_component.rb +3 -3
  34. data/app/components/blacklight/document_title_component.rb +3 -10
  35. data/app/components/blacklight/facet_field_checkboxes_component.rb +2 -20
  36. data/app/components/blacklight/facet_field_component.rb +2 -17
  37. data/app/components/blacklight/facet_field_filter_component.rb +2 -21
  38. data/app/components/blacklight/facet_field_inclusive_constraint_component.rb +4 -25
  39. data/app/components/blacklight/facet_field_list_component.rb +2 -32
  40. data/app/components/blacklight/facet_field_no_layout_component.rb +2 -10
  41. data/app/components/blacklight/facet_field_pagination_component.html.erb +2 -2
  42. data/app/components/blacklight/facet_item_component.rb +2 -74
  43. data/app/components/blacklight/facet_item_pivot_component.rb +1 -1
  44. data/app/components/blacklight/facets/checkboxes_component.rb +26 -0
  45. data/app/components/blacklight/facets/count_component.rb +23 -0
  46. data/app/components/blacklight/{facet_field_component.html.erb → facets/field_component.html.erb} +1 -1
  47. data/app/components/blacklight/facets/field_component.rb +23 -0
  48. data/app/components/blacklight/facets/filters_component.html.erb +4 -0
  49. data/app/components/blacklight/facets/filters_component.rb +27 -0
  50. data/app/components/blacklight/{facet_field_inclusive_constraint_component.html.erb → facets/inclusive_constraint_component.html.erb} +1 -1
  51. data/app/components/blacklight/facets/inclusive_constraint_component.rb +31 -0
  52. data/app/components/blacklight/{facet_field_filter_component.html.erb → facets/index_navigation_component.html.erb} +1 -1
  53. data/app/components/blacklight/facets/index_navigation_component.rb +32 -0
  54. data/app/components/blacklight/facets/item_component.rb +73 -0
  55. data/app/components/blacklight/facets/list_component.html.erb +11 -0
  56. data/app/components/blacklight/facets/list_component.rb +38 -0
  57. data/app/components/blacklight/facets/no_layout_component.rb +16 -0
  58. data/app/components/blacklight/facets/selected_value_component.rb +29 -0
  59. data/app/components/blacklight/facets/suggest_component.html.erb +12 -0
  60. data/app/components/blacklight/facets/suggest_component.rb +22 -0
  61. data/app/components/blacklight/metadata_field_plain_text_layout_component.rb +2 -2
  62. data/app/components/blacklight/response/facet_group_component.html.erb +1 -1
  63. data/app/components/blacklight/response/facet_group_component.rb +5 -1
  64. data/app/components/blacklight/system/dropdown_component.html.erb +1 -1
  65. data/app/components/blacklight/system/dropdown_component.rb +1 -1
  66. data/app/components/blacklight/top_navbar_component.html.erb +1 -1
  67. data/app/controllers/concerns/blacklight/bookmarks.rb +3 -3
  68. data/app/controllers/concerns/blacklight/catalog.rb +10 -25
  69. data/app/controllers/concerns/blacklight/controller.rb +1 -1
  70. data/app/controllers/concerns/blacklight/facetable.rb +34 -0
  71. data/app/controllers/concerns/blacklight/search_context.rb +1 -1
  72. data/app/controllers/concerns/blacklight/searchable.rb +1 -1
  73. data/app/helpers/blacklight/configuration_helper_behavior.rb +2 -2
  74. data/app/helpers/blacklight/document_helper_behavior.rb +3 -1
  75. data/app/helpers/blacklight/facets_helper_behavior.rb +9 -0
  76. data/app/helpers/blacklight/icon_helper_behavior.rb +2 -2
  77. data/app/javascript/blacklight-frontend/checkbox_submit.js +3 -0
  78. data/app/javascript/blacklight-frontend/debounce.js +1 -1
  79. data/app/javascript/blacklight-frontend/facet_suggest.js +23 -3
  80. data/app/javascript/blacklight-frontend/index.js +0 -2
  81. data/app/javascript/blacklight-frontend/modal.js +1 -4
  82. data/app/javascript/blacklight-frontend/search_context.js +3 -2
  83. data/app/models/facet_search_builder.rb +5 -0
  84. data/app/presenters/blacklight/facet_field_presenter.rb +1 -1
  85. data/app/presenters/blacklight/json_presenter.rb +1 -3
  86. data/app/presenters/blacklight/rendering/helper_method.rb +4 -4
  87. data/app/presenters/blacklight/rendering/join.rb +2 -2
  88. data/app/services/blacklight/facet_search_service.rb +44 -0
  89. data/app/services/blacklight/field_retriever.rb +1 -1
  90. data/app/services/blacklight/search_service.rb +6 -6
  91. data/app/values/blacklight/types.rb +2 -2
  92. data/app/views/catalog/_facet_pivot.html.erb +1 -1
  93. data/app/views/catalog/_home_text.html.erb +2 -2
  94. data/app/views/catalog/_sort_and_per_page.html.erb +1 -1
  95. data/app/views/catalog/facet.html.erb +8 -10
  96. data/config/locales/blacklight.ar.yml +2 -2
  97. data/config/locales/blacklight.es.yml +2 -2
  98. data/config/locales/blacklight.fr.yml +2 -2
  99. data/config/locales/blacklight.hu.yml +2 -2
  100. data/config/locales/blacklight.it.yml +2 -2
  101. data/config/locales/blacklight.nl.yml +1 -1
  102. data/config/locales/blacklight.pt-BR.yml +2 -2
  103. data/config/locales/blacklight.sq.yml +2 -2
  104. data/config/locales/blacklight.zh.yml +2 -2
  105. data/lib/blacklight/abstract_repository.rb +2 -2
  106. data/lib/blacklight/abstract_search_builder.rb +154 -0
  107. data/lib/blacklight/configuration/context.rb +3 -3
  108. data/lib/blacklight/configuration/facet_field.rb +6 -6
  109. data/lib/blacklight/configuration/field.rb +4 -4
  110. data/lib/blacklight/configuration/fields.rb +0 -1
  111. data/lib/blacklight/configuration/search_field.rb +1 -1
  112. data/lib/blacklight/configuration/view_config.rb +2 -2
  113. data/lib/blacklight/configuration.rb +6 -7
  114. data/lib/blacklight/facet_search_builder.rb +18 -0
  115. data/lib/blacklight/nested_open_struct_with_hash_access.rb +1 -1
  116. data/lib/blacklight/open_struct_with_hash_access.rb +2 -2
  117. data/lib/blacklight/search_builder.rb +1 -159
  118. data/lib/blacklight/search_state/filter_field.rb +4 -4
  119. data/lib/blacklight/search_state/pivot_filter_field.rb +4 -4
  120. data/lib/blacklight/solr/abstract_filter_query_builder.rb +77 -0
  121. data/lib/blacklight/solr/default_filter_query_builder.rb +20 -0
  122. data/lib/blacklight/solr/facet_search_builder_behavior.rb +62 -0
  123. data/lib/blacklight/solr/repository.rb +8 -9
  124. data/lib/blacklight/solr/response/facets.rb +2 -2
  125. data/lib/blacklight/solr/response/params.rb +0 -4
  126. data/lib/blacklight/solr/response.rb +5 -1
  127. data/lib/blacklight/solr/search_builder_behavior.rb +17 -132
  128. data/lib/blacklight.rb +1 -1
  129. data/lib/generators/blacklight/assets/importmap_generator.rb +3 -5
  130. data/lib/generators/blacklight/assets_generator.rb +1 -1
  131. data/lib/generators/blacklight/search_builder_generator.rb +1 -1
  132. data/lib/generators/blacklight/templates/.solr_wrapper.yml +2 -0
  133. data/lib/generators/blacklight/templates/catalog_controller.rb +3 -1
  134. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -4
  135. data/package.json +3 -3
  136. data/spec/components/blacklight/advanced_search_form_component_spec.rb +18 -22
  137. data/spec/components/blacklight/constraint_layout_component_spec.rb +8 -8
  138. data/spec/components/blacklight/constraints_component_spec.rb +11 -11
  139. data/spec/components/blacklight/document/action_component_spec.rb +23 -15
  140. data/spec/components/blacklight/document/group_component_spec.rb +10 -15
  141. data/spec/components/blacklight/document/page_header_component_spec.rb +35 -28
  142. data/spec/components/blacklight/document/sidebar_component_spec.rb +5 -11
  143. data/spec/components/blacklight/document_component_spec.rb +98 -65
  144. data/spec/components/blacklight/facet_component_spec.rb +12 -8
  145. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +12 -12
  146. data/spec/components/blacklight/{facet_field_checkboxes_component_spec.rb → facets/checkboxes_component_spec.rb} +13 -13
  147. data/spec/components/blacklight/facets/filters_component_spec.rb +36 -0
  148. data/spec/components/blacklight/facets/index_navigation_component_spec.rb +40 -0
  149. data/spec/components/blacklight/{facet_item_component_spec.rb → facets/item_component_spec.rb} +10 -10
  150. data/spec/components/blacklight/{facet_field_list_component_spec.rb → facets/list_component_spec.rb} +23 -23
  151. data/spec/components/blacklight/facets/suggest_component_spec.rb +68 -0
  152. data/spec/components/blacklight/header_component_spec.rb +2 -4
  153. data/spec/components/blacklight/hidden_search_state_component_spec.rb +7 -7
  154. data/spec/components/blacklight/metadata_field_component_spec.rb +17 -15
  155. data/spec/components/blacklight/response/facet_group_component_spec.rb +37 -0
  156. data/spec/components/blacklight/response/pagination_component_spec.rb +1 -1
  157. data/spec/components/blacklight/response/spellcheck_component_spec.rb +1 -1
  158. data/spec/components/blacklight/search_bar_component_spec.rb +4 -4
  159. data/spec/components/blacklight/search_context/server_applied_params_component_spec.rb +2 -2
  160. data/spec/components/blacklight/search_context/server_item_pagination_component_spec.rb +3 -5
  161. data/spec/components/blacklight/skip_link_component_spec.rb +8 -11
  162. data/spec/components/blacklight/start_over_button_component_spec.rb +4 -4
  163. data/spec/components/blacklight/system/dropdown_component_spec.rb +26 -0
  164. data/spec/components/blacklight/system/flash_message_component_spec.rb +7 -11
  165. data/spec/controllers/catalog_controller_spec.rb +12 -20
  166. data/spec/features/facets_spec.rb +70 -7
  167. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +10 -0
  168. data/spec/lib/blacklight/configuration/facet_field_spec.rb +2 -2
  169. data/spec/lib/blacklight/parameters_spec.rb +12 -1
  170. data/spec/lib/blacklight/search_state/filter_field_spec.rb +18 -0
  171. data/spec/models/blacklight/configuration_spec.rb +32 -28
  172. data/spec/models/blacklight/facet_search_builder_spec.rb +19 -0
  173. data/spec/models/blacklight/search_builder_spec.rb +1 -11
  174. data/spec/models/blacklight/solr/default_filter_query_builder_spec.rb +72 -0
  175. data/spec/models/blacklight/solr/document_spec.rb +0 -4
  176. data/spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb +929 -0
  177. data/spec/models/blacklight/solr/repository_spec.rb +31 -29
  178. data/spec/models/blacklight/solr/response/facets_spec.rb +86 -40
  179. data/spec/models/blacklight/solr/response/group_response_spec.rb +8 -5
  180. data/spec/models/blacklight/solr/response/group_spec.rb +9 -5
  181. data/spec/models/blacklight/solr/response_spec.rb +96 -64
  182. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +2 -227
  183. data/spec/models/solr_document_spec.rb +5 -1
  184. data/spec/services/blacklight/search_service_spec.rb +6 -27
  185. data/spec/spec_helper.rb +0 -1
  186. data/spec/support/view_component_test_helpers.rb +0 -18
  187. data/spec/views/catalog/facet.html.erb_spec.rb +10 -3
  188. data/spec/views/catalog/index.atom.builder_spec.rb +6 -3
  189. data/spec/views/catalog/index.html.erb_spec.rb +3 -1
  190. metadata +58 -29
  191. data/.github/workflows/ruby.yml +0 -98
  192. data/app/components/blacklight/facet_field_list_component.html.erb +0 -19
  193. data/app/components/blacklight/search/facet_suggest_input.html.erb +0 -9
  194. data/app/components/blacklight/search/facet_suggest_input.rb +0 -16
  195. data/app/javascript/blacklight-frontend/modalForm.js +0 -60
  196. data/app/views/catalog/_facet_index_navigation.html.erb +0 -1
  197. data/app/views/catalog/_facet_layout.html.erb +0 -8
  198. data/app/views/catalog/_facet_pagination.html.erb +0 -1
  199. data/spec/components/blacklight/document_metadata_component_spec.rb +0 -0
  200. data/spec/components/blacklight/search/facet_suggest_input_spec.rb +0 -33
  201. data/spec/views/catalog/_facet_index_navigation.html.erb_spec.rb +0 -43
  202. data/spec/views/catalog/_facet_layout.html.erb_spec.rb +0 -41
  203. /data/app/components/blacklight/{facet_field_checkboxes_component.html.erb → facets/checkboxes_component.html.erb} +0 -0
@@ -44,26 +44,6 @@ RSpec.describe Blacklight::Solr::Repository, :api do
44
44
  end
45
45
  end
46
46
 
47
- context "with legacy request handler-based configuration" do
48
- before do
49
- blacklight_config.document_solr_path = 'select'
50
- blacklight_config.document_unique_id_param = :id
51
- end
52
-
53
- it "uses the provided :qt param" do
54
- blacklight_config.document_solr_request_handler = 'xyz'
55
- allow(subject.connection).to receive(:send_and_receive).with('select', hash_including(params: { id: '123', qt: 'abc' })).and_return(mock_response)
56
- expect(subject.find("123", qt: 'abc')).to be_a Blacklight::Solr::Response
57
- end
58
-
59
- it "uses the :qt parameter from the default_document_solr_params" do
60
- blacklight_config.default_document_solr_params[:qt] = 'abc'
61
- blacklight_config.document_solr_request_handler = 'xyz'
62
- allow(subject.connection).to receive(:send_and_receive).with('select', hash_including(params: { id: '123', qt: 'abc' })).and_return(mock_response)
63
- expect(subject.find("123")).to be_a Blacklight::Solr::Response
64
- end
65
- end
66
-
67
47
  it "preserves the class of the incoming params" do
68
48
  doc_params = ActiveSupport::HashWithIndifferentAccess.new
69
49
  allow(subject.connection).to receive(:send_and_receive).with('get', anything).and_return(mock_response)
@@ -92,27 +72,36 @@ RSpec.describe Blacklight::Solr::Repository, :api do
92
72
  end
93
73
 
94
74
  describe "#search" do
75
+ context 'with positional params' do
76
+ it "uses the search-specific solr path" do
77
+ blacklight_config.solr_path = 'xyz'
78
+ allow(subject.connection).to receive(:send_and_receive).with('xyz', anything).and_return(mock_response)
79
+ allow(Blacklight.deprecation).to receive(:warn)
80
+ expect(subject.search({})).to be_a Blacklight::Solr::Response
81
+ end
82
+ end
83
+
95
84
  it "uses the search-specific solr path" do
96
85
  blacklight_config.solr_path = 'xyz'
97
86
  allow(subject.connection).to receive(:send_and_receive).with('xyz', anything).and_return(mock_response)
98
- expect(subject.search({})).to be_a Blacklight::Solr::Response
87
+ expect(subject.search(params: {})).to be_a Blacklight::Solr::Response
99
88
  end
100
89
 
101
90
  it "uses the default solr path" do
102
91
  allow(subject.connection).to receive(:send_and_receive).with('select', anything).and_return(mock_response)
103
- expect(subject.search({})).to be_a Blacklight::Solr::Response
92
+ expect(subject.search(params: {})).to be_a Blacklight::Solr::Response
104
93
  end
105
94
 
106
95
  it "uses a default :qt param" do
107
96
  blacklight_config.qt = 'xyz'
108
97
  allow(subject.connection).to receive(:send_and_receive).with('select', hash_including(params: { qt: 'xyz' })).and_return(mock_response)
109
- expect(subject.search({})).to be_a Blacklight::Solr::Response
98
+ expect(subject.search(params: {})).to be_a Blacklight::Solr::Response
110
99
  end
111
100
 
112
101
  it "uses the provided :qt param" do
113
102
  blacklight_config.qt = 'xyz'
114
103
  allow(subject.connection).to receive(:send_and_receive).with('select', hash_including(params: { qt: 'abc' })).and_return(mock_response)
115
- expect(subject.search(qt: 'abc')).to be_a Blacklight::Solr::Response
104
+ expect(subject.search(params: { qt: 'abc' })).to be_a Blacklight::Solr::Response
116
105
  end
117
106
 
118
107
  it "preserves the class of the incoming params" do
@@ -120,7 +109,7 @@ RSpec.describe Blacklight::Solr::Repository, :api do
120
109
  search_params[:q] = "query"
121
110
  allow(subject.connection).to receive(:send_and_receive).with('select', anything).and_return(mock_response)
122
111
 
123
- response = subject.search(search_params)
112
+ response = subject.search(params: search_params)
124
113
  expect(response).to be_a Blacklight::Solr::Response
125
114
  expect(response.params).to be_a ActiveSupport::HashWithIndifferentAccess
126
115
  end
@@ -133,7 +122,20 @@ RSpec.describe Blacklight::Solr::Repository, :api do
133
122
  expect(params[:method]).to eq :get
134
123
  expect(params[:params]).to include input_params
135
124
  end.and_return('response' => { 'docs' => [] })
136
- subject.search(input_params)
125
+ subject.search(params: input_params)
126
+ end
127
+
128
+ it "raises a Blacklight exception if RSolr can't connect to the Solr instance" do
129
+ allow(repository.connection).to receive(:send_and_receive).and_raise(Errno::ECONNREFUSED)
130
+ expect { subject.search(params: {}) }.to raise_exception(/Unable to connect to Solr instance/)
131
+ end
132
+
133
+ it "raises a Blacklight exception if RSolr raises a timeout error connecting to Solr instance" do
134
+ rsolr_timeout = RSolr::Error::Timeout.new(nil, nil)
135
+ allow(rsolr_timeout).to receive(:to_s).and_return("mocked RSolr timeout")
136
+
137
+ allow(repository.connection).to receive(:send_and_receive).and_raise(rsolr_timeout)
138
+ expect { subject.search(params: {}) }.to raise_exception(Blacklight::Exceptions::RepositoryTimeout, /Timeout connecting to Solr instance/)
137
139
  end
138
140
  end
139
141
 
@@ -182,7 +184,7 @@ RSpec.describe Blacklight::Solr::Repository, :api do
182
184
  allow(subject.connection).to receive(:send_and_receive) do |path|
183
185
  expect(path).to eq 'xyz'
184
186
  end
185
- subject.search(input_params)
187
+ subject.search(params: input_params)
186
188
  end
187
189
  end
188
190
 
@@ -195,7 +197,7 @@ RSpec.describe Blacklight::Solr::Repository, :api do
195
197
  allow(subject.connection).to receive(:send_and_receive) do |path|
196
198
  expect(path).to eq 'my-great-json'
197
199
  end
198
- subject.search(input_params)
200
+ subject.search(params: input_params)
199
201
  end
200
202
  end
201
203
  end
@@ -205,7 +207,7 @@ RSpec.describe Blacklight::Solr::Repository, :api do
205
207
  let (:blacklight_config) { config = Blacklight::Configuration.new; config.http_method = :post; config }
206
208
 
207
209
  it "sends a post request to solr and get a response back" do
208
- response = subject.search(q: all_docs_query)
210
+ response = subject.search(params: { q: all_docs_query })
209
211
  expect(response.docs.length).to be >= 1
210
212
  end
211
213
  end
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Blacklight::Solr::Response::Facets, :api do
4
+ let(:search_builder) do
5
+ Blacklight::SearchBuilder.new(view_context)
6
+ end
7
+ let(:view_context) do
8
+ double("View context", blacklight_config: CatalogController.blacklight_config.deep_copy)
9
+ end
10
+
4
11
  describe Blacklight::Solr::Response::Facets::FacetField do
5
12
  describe "A field with default options" do
6
13
  subject(:field) { described_class.new "my_field", [] }
@@ -60,22 +67,29 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
60
67
  end
61
68
 
62
69
  describe "#aggregations" do
63
- subject { Blacklight::Solr::Response.new({ responseHeader: response_header, facet_counts: { facet_fields: [facet_field] } }, request_params) }
70
+ subject { Blacklight::Solr::Response.new({ responseHeader: {}, facet_counts: { facet_fields: [facet_field] } }, search_builder) }
64
71
 
65
72
  let(:facet_field) { ['my_field', []] }
66
- let(:response_header) { { params: request_params } }
67
- let(:request_params) { {} }
68
73
 
69
74
  describe "#limit" do
70
- it "extracts a field-specific limit value" do
71
- request_params['f.my_field.facet.limit'] = "10"
72
- request_params['facet.limit'] = "15"
73
- expect(subject.aggregations['my_field'].limit).to eq 10
75
+ context 'with a field-specific limit value' do
76
+ before do
77
+ search_builder.merge('f.my_field.facet.limit' => '10', 'facet.limit' => '15')
78
+ end
79
+
80
+ it "extracts a field-specific limit value" do
81
+ expect(subject.aggregations['my_field'].limit).to eq 10
82
+ end
74
83
  end
75
84
 
76
- it "extracts a global limit value" do
77
- request_params['facet.limit'] = "15"
78
- expect(subject.aggregations['my_field'].limit).to eq 15
85
+ context 'with a global limit value' do
86
+ before do
87
+ search_builder.merge('facet.limit' => '15')
88
+ end
89
+
90
+ it "extracts a global limit value" do
91
+ expect(subject.aggregations['my_field'].limit).to eq 15
92
+ end
79
93
  end
80
94
 
81
95
  it "is the solr default limit if no value is found" do
@@ -84,15 +98,24 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
84
98
  end
85
99
 
86
100
  describe "#offset" do
87
- it "extracts a field-specific offset value" do
88
- request_params['f.my_field.facet.offset'] = "10"
89
- request_params['facet.offset'] = "15"
90
- expect(subject.aggregations['my_field'].offset).to eq 10
101
+ context 'with a field-specific offset value' do
102
+ before do
103
+ search_builder.merge('f.my_field.facet.offset' => '10', 'facet.offset' => '15')
104
+ end
105
+
106
+ it "extracts a field-specific offset value" do
107
+ expect(subject.aggregations['my_field'].offset).to eq 10
108
+ end
91
109
  end
92
110
 
93
- it "extracts a global offset value" do
94
- request_params['facet.offset'] = "15"
95
- expect(subject.aggregations['my_field'].offset).to eq 15
111
+ context 'with a global offset value' do
112
+ before do
113
+ search_builder.merge('facet.offset' => '15')
114
+ end
115
+
116
+ it "extracts a global offset value" do
117
+ expect(subject.aggregations['my_field'].offset).to eq 15
118
+ end
96
119
  end
97
120
 
98
121
  it "is nil if no value is found" do
@@ -101,15 +124,24 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
101
124
  end
102
125
 
103
126
  describe "#sort" do
104
- it "extracts a field-specific sort value" do
105
- request_params['f.my_field.facet.sort'] = "alpha"
106
- request_params['facet.sort'] = "index"
107
- expect(subject.aggregations['my_field'].sort).to eq 'alpha'
127
+ context 'with a field-specific sort value' do
128
+ before do
129
+ search_builder.merge('f.my_field.facet.sort' => 'alpha', 'facet.sort' => 'index')
130
+ end
131
+
132
+ it "extracts a field-specific sort value" do
133
+ expect(subject.aggregations['my_field'].sort).to eq 'alpha'
134
+ end
108
135
  end
109
136
 
110
- it "extracts a global sort value" do
111
- request_params['facet.sort'] = "alpha"
112
- expect(subject.aggregations['my_field'].sort).to eq 'alpha'
137
+ context 'with a global sort value' do
138
+ before do
139
+ search_builder.merge('facet.sort' => 'alpha')
140
+ end
141
+
142
+ it "extracts a global sort value" do
143
+ expect(subject.aggregations['my_field'].sort).to eq 'alpha'
144
+ end
113
145
  end
114
146
 
115
147
  it "defaults to count if no value is found and the default limit is used" do
@@ -117,23 +149,37 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
117
149
  expect(subject.aggregations['my_field'].count?).to be true
118
150
  end
119
151
 
120
- it "defaults to index if no value is found and the limit is unlimited" do
121
- request_params['facet.limit'] = -1
122
- expect(subject.aggregations['my_field'].sort).to eq 'index'
123
- expect(subject.aggregations['my_field'].index?).to be true
152
+ context 'when no value is found and the limit is unlimited' do
153
+ before do
154
+ search_builder.merge('facet.limit' => -1)
155
+ end
156
+
157
+ it "defaults to index" do
158
+ expect(subject.aggregations['my_field'].sort).to eq 'index'
159
+ expect(subject.aggregations['my_field'].index?).to be true
160
+ end
124
161
  end
125
162
  end
126
163
 
127
164
  describe '#prefix' do
128
- it 'extracts field-specific prefix values' do
129
- request_params['f.my_field.facet.prefix'] = "a"
130
- request_params['facet.prefix'] = "b"
131
- expect(subject.aggregations['my_field'].prefix).to eq 'a'
165
+ context 'with a field-specific prefix value' do
166
+ before do
167
+ search_builder.merge('f.my_field.facet.prefix' => 'a', 'facet.prefix' => 'b')
168
+ end
169
+
170
+ it "extracts a field-specific prefix value" do
171
+ expect(subject.aggregations['my_field'].prefix).to eq 'a'
172
+ end
132
173
  end
133
174
 
134
- it "extracts a global sort value" do
135
- request_params['facet.prefix'] = "abc"
136
- expect(subject.aggregations['my_field'].prefix).to eq 'abc'
175
+ context 'with a global prefix value' do
176
+ before do
177
+ search_builder.merge('facet.prefix' => 'abc')
178
+ end
179
+
180
+ it "extracts a global prefix value" do
181
+ expect(subject.aggregations['my_field'].prefix).to eq 'abc'
182
+ end
137
183
  end
138
184
 
139
185
  it "defaults to no prefix value" do
@@ -149,7 +195,7 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
149
195
  end
150
196
 
151
197
  describe "#merge_facet" do
152
- let(:response) { Blacklight::Solr::Response.new(facet_counts, {}, {}) }
198
+ let(:response) { Blacklight::Solr::Response.new(facet_counts, search_builder, {}) }
153
199
  let(:facet) { { name: "foo", value: "bar", hits: 1 } }
154
200
 
155
201
  before do
@@ -186,7 +232,7 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
186
232
  end
187
233
 
188
234
  context "facet.missing" do
189
- subject { Blacklight::Solr::Response.new(response, {}) }
235
+ subject { Blacklight::Solr::Response.new(response, search_builder) }
190
236
 
191
237
  let(:response) do
192
238
  {
@@ -213,7 +259,7 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
213
259
  end
214
260
 
215
261
  describe "query facets" do
216
- subject { Blacklight::Solr::Response.new(response, {}, blacklight_config: blacklight_config) }
262
+ subject { Blacklight::Solr::Response.new(response, search_builder, blacklight_config: blacklight_config) }
217
263
 
218
264
  let(:facet_config) do
219
265
  double(
@@ -288,7 +334,7 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
288
334
  end
289
335
 
290
336
  describe "pivot facets" do
291
- subject { Blacklight::Solr::Response.new(response, {}, blacklight_config: blacklight_config) }
337
+ subject { Blacklight::Solr::Response.new(response, search_builder, blacklight_config: blacklight_config) }
292
338
 
293
339
  let(:facet_config) do
294
340
  double(key: 'my_pivot_facet_field', query: nil, pivot: %w[field_a field_b])
@@ -330,7 +376,7 @@ RSpec.describe Blacklight::Solr::Response::Facets, :api do
330
376
  end
331
377
 
332
378
  describe 'json facets' do
333
- subject { Blacklight::Solr::Response.new(response, {}, blacklight_config: blacklight_config) }
379
+ subject { Blacklight::Solr::Response.new(response, search_builder, blacklight_config: blacklight_config) }
334
380
 
335
381
  let(:response) do
336
382
  {
@@ -4,7 +4,14 @@ require "spec_helper"
4
4
 
5
5
  RSpec.describe Blacklight::Solr::Response::GroupResponse, :api do
6
6
  let(:response) do
7
- create_response(sample_response)
7
+ Blacklight::Solr::Response.new(sample_response, search_builder)
8
+ end
9
+
10
+ let(:search_builder) do
11
+ Blacklight::SearchBuilder.new(view_context).tap { |b| b.rows = 3 }
12
+ end
13
+ let(:view_context) do
14
+ double("View context", blacklight_config: CatalogController.blacklight_config.deep_copy)
8
15
  end
9
16
 
10
17
  let(:group) do
@@ -82,10 +89,6 @@ RSpec.describe Blacklight::Solr::Response::GroupResponse, :api do
82
89
  end
83
90
  end
84
91
 
85
- def create_response(response, params = {})
86
- Blacklight::Solr::Response.new(response, params)
87
- end
88
-
89
92
  def sample_response
90
93
  { "responseHeader" => { "params" => { "rows" => 3, "group.limit" => 5 } },
91
94
  "grouped" =>
@@ -7,8 +7,16 @@ RSpec.describe Blacklight::Solr::Response::Group, :api do
7
7
  group.groups.first
8
8
  end
9
9
 
10
+ let(:search_builder) do
11
+ Blacklight::SearchBuilder.new(view_context)
12
+ end
13
+
14
+ let(:view_context) do
15
+ double("View context", blacklight_config: CatalogController.blacklight_config.deep_copy)
16
+ end
17
+
10
18
  let(:response) do
11
- create_response(sample_response)
19
+ Blacklight::Solr::Response.new(sample_response, search_builder)
12
20
  end
13
21
 
14
22
  let(:group) do
@@ -51,10 +59,6 @@ RSpec.describe Blacklight::Solr::Response::Group, :api do
51
59
  end
52
60
  end
53
61
 
54
- def create_response(response, params = {})
55
- Blacklight::Solr::Response.new(response, params)
56
- end
57
-
58
62
  def sample_response
59
63
  { "responseHeader" => { "params" => { "rows" => 3, "group.limit" => 5 } },
60
64
  "grouped" =>
@@ -3,16 +3,17 @@
3
3
  require 'rspec-benchmark'
4
4
 
5
5
  RSpec.describe Blacklight::Solr::Response, :api do
6
- let(:raw_response) { eval(mock_query_response) }
7
-
8
- let(:config) { Blacklight::Configuration.new }
9
-
10
- let(:r) do
6
+ subject(:r) do
11
7
  described_class.new(raw_response,
12
- raw_response['params'],
8
+ request_params,
13
9
  blacklight_config: config)
14
10
  end
15
11
 
12
+ let(:raw_response) { eval(mock_query_response) }
13
+
14
+ let(:config) { Blacklight::Configuration.new }
15
+ let(:request_params) { raw_response['params'] }
16
+
16
17
  it 'creates a valid response' do
17
18
  expect(r).to respond_to(:header)
18
19
  end
@@ -134,113 +135,144 @@ RSpec.describe Blacklight::Solr::Response, :api do
134
135
  expect(facet.name).to eq 'cat'
135
136
  end
136
137
 
137
- it 'provides the responseHeader params' do
138
- raw_response = eval(mock_query_response)
139
- raw_response['responseHeader']['params']['test'] = :test
140
- r = described_class.new(raw_response, raw_response['params'])
141
- expect(r.params['test']).to eq :test
138
+ context 'with responseHeader params' do
139
+ let(:raw_response) do
140
+ eval(mock_query_response).tap do |resp|
141
+ resp['responseHeader']['params']['test'] = :test
142
+ end
143
+ end
144
+
145
+ it 'provides the responseHeader params' do
146
+ expect(r.params['test']).to eq :test
147
+ end
142
148
  end
143
149
 
144
- it 'extracts json params' do
145
- raw_response = eval(mock_query_response)
146
- raw_response['responseHeader']['params']['test'] = 'from query'
147
- raw_response['responseHeader']['params'].delete('rows')
148
- raw_response['responseHeader']['params']['json'] = { limit: 5, params: { test: 'from json params' } }.to_json
149
- r = described_class.new(raw_response, raw_response['params'])
150
- expect(r.params['test']).to eq 'from query'
151
- expect(r.rows).to eq 5
150
+ context 'with json params' do
151
+ let(:raw_response) do
152
+ eval(mock_response_with_spellcheck).tap do |resp|
153
+ resp['responseHeader']['params']['test'] = 'from query'
154
+ resp['responseHeader']['params'].delete('rows')
155
+ resp['responseHeader']['params']['json'] = { limit: 5, params: { test: 'from json params' } }.to_json
156
+ end
157
+ end
158
+
159
+ it 'extracts json params' do
160
+ expect(r.params['test']).to eq 'from query'
161
+ expect(r.rows).to eq 5
162
+ end
152
163
  end
153
164
 
154
165
  it 'provides the solr-returned params and "rows" should be 11' do
155
- raw_response = eval(mock_query_response)
156
- r = described_class.new(raw_response, {})
157
166
  expect(r.params[:rows].to_s).to eq '11'
158
167
  expect(r.params[:sort]).to eq 'title_si asc, pub_date_si desc'
159
168
  end
160
169
 
161
- it 'provides the ruby request params if responseHeader["params"] does not exist' do
162
- raw_response = eval(mock_query_response)
163
- raw_response.delete 'responseHeader'
164
- r = described_class.new(raw_response, rows: 999, sort: 'score desc, pub_date_si desc, title_si asc')
165
- expect(r.params[:rows].to_s).to eq '999'
166
- expect(r.params[:sort]).to eq 'score desc, pub_date_si desc, title_si asc'
170
+ context 'when responseHeader["params"] does not exist' do
171
+ before do
172
+ raw_response.delete 'responseHeader'
173
+ end
174
+
175
+ let(:request_params) { { rows: 999, sort: 'score desc, pub_date_si desc, title_si asc' } }
176
+
177
+ it 'provides the ruby request params' do
178
+ expect(r.params[:rows].to_s).to eq '999'
179
+ expect(r.params[:sort]).to eq 'score desc, pub_date_si desc, title_si asc'
180
+ end
167
181
  end
168
182
 
169
- it 'provides spelling suggestions for regular spellcheck results' do
170
- raw_response = eval(mock_response_with_spellcheck)
171
- r = described_class.new(raw_response, {})
172
- expect(r.spelling.words).to include("dell")
173
- expect(r.spelling.words).to include("ultrasharp")
183
+ context 'with regular spellcheck results' do
184
+ let(:raw_response) { eval(mock_response_with_spellcheck) }
185
+ let(:request_params) { {} }
186
+
187
+ it 'provides spelling suggestions' do
188
+ expect(r.spelling.words).to include("dell")
189
+ expect(r.spelling.words).to include("ultrasharp")
190
+ end
174
191
  end
175
192
 
176
- it 'provides spelling suggestions for extended spellcheck results' do
177
- raw_response = eval(mock_response_with_spellcheck_extended)
178
- r = described_class.new(raw_response, {})
179
- expect(r.spelling.words).to include("dell")
180
- expect(r.spelling.words).to include("ultrasharp")
193
+ context 'with extended spellcheck results' do
194
+ let(:raw_response) { eval(mock_response_with_spellcheck_extended) }
195
+ let(:request_params) { {} }
196
+
197
+ it 'provides spelling suggestions' do
198
+ expect(r.spelling.words).to include("dell")
199
+ expect(r.spelling.words).to include("ultrasharp")
200
+ end
181
201
  end
182
202
 
183
- it 'provides no spelling suggestions when extended results and suggestion frequency is the same as original query frequency' do
184
- raw_response = eval(mock_response_with_spellcheck_same_frequency)
185
- r = described_class.new(raw_response, {})
186
- expect(r.spelling.words).to eq []
203
+ context 'when extended results and suggestion frequency is the same as original query frequency' do
204
+ let(:raw_response) { eval(mock_response_with_spellcheck_same_frequency) }
205
+ let(:request_params) { {} }
206
+
207
+ it 'provides no spelling suggestions' do
208
+ expect(r.spelling.words).to eq []
209
+ end
187
210
  end
188
211
 
189
- context "pre solr 5 spellcheck collation syntax" do
212
+ context "with pre solr 5 spellcheck collation syntax" do
213
+ let(:raw_response) { eval(mock_response_with_spellcheck_collation) }
214
+ let(:request_params) { {} }
215
+
190
216
  it 'provides spelling suggestions for a regular spellcheck results with a collation' do
191
- raw_response = eval(mock_response_with_spellcheck_collation)
192
- r = described_class.new(raw_response, {})
193
217
  expect(r.spelling.words).to include("dell")
194
218
  expect(r.spelling.words).to include("ultrasharp")
195
219
  end
196
220
 
197
221
  it 'provides spelling suggestion collation' do
198
- raw_response = eval(mock_response_with_spellcheck_collation)
199
- r = described_class.new(raw_response, {})
200
222
  expect(r.spelling.collation).to eq 'dell ultrasharp'
201
223
  end
202
224
  end
203
225
 
204
- context "solr 5 spellcheck collation syntax" do
226
+ context "with solr 5 spellcheck collation syntax" do
227
+ let(:raw_response) { eval(mock_response_with_spellcheck_collation_solr5) }
228
+ let(:request_params) { {} }
229
+
205
230
  it 'provides spelling suggestions for a regular spellcheck results with a collation' do
206
- raw_response = eval(mock_response_with_spellcheck_collation_solr5)
207
- r = described_class.new(raw_response, {})
208
231
  expect(r.spelling.words).to include("dell")
209
232
  expect(r.spelling.words).to include("ultrasharp")
210
233
  end
211
234
 
212
235
  it 'provides spelling suggestion collation' do
213
- raw_response = eval(mock_response_with_spellcheck_collation_solr5)
214
- r = described_class.new(raw_response, {})
215
236
  expect(r.spelling.collation).to eq 'dell ultrasharp'
216
237
  end
217
238
  end
218
239
 
219
- context 'solr 6.5 spellcheck collation syntax' do
240
+ context 'with solr 6.5 spellcheck collation syntax' do
241
+ let(:raw_response) { eval(mock_response_with_spellcheck_collation_solr65) }
242
+ let(:request_params) { {} }
243
+
220
244
  it 'provides spelling suggestions for a regular spellcheck results with a collation' do
221
- raw_response = eval(mock_response_with_spellcheck_collation_solr65)
222
- r = described_class.new(raw_response, {})
223
245
  expect(r.spelling.words).to include("dell")
224
246
  expect(r.spelling.words).to include("ultrasharp")
225
247
  end
226
248
  end
227
249
 
228
- it "provides MoreLikeThis suggestions" do
229
- raw_response = eval(mock_response_with_more_like_this)
230
- r = described_class.new(raw_response, {})
231
- expect(r.more_like(double(id: '79930185'))).to have(2).items
250
+ context 'with moreLikeThis suggstions' do
251
+ let(:raw_response) { eval(mock_response_with_more_like_this) }
252
+ let(:request_params) { {} }
253
+
254
+ it "provides MoreLikeThis suggestions" do
255
+ expect(r.more_like(double(id: '79930185'))).to have(2).items
256
+ end
232
257
  end
233
258
 
234
- it "is empty when the response has no results" do
235
- r = described_class.new({}, {})
236
- allow(r).to receive_messages(total: 0)
237
- expect(r).to be_empty
259
+ context 'with no results' do
260
+ let(:raw_response) { {} }
261
+ let(:request_params) { {} }
262
+
263
+ it "is empty when the response has no results" do
264
+ expect(r).to be_empty
265
+ end
238
266
  end
239
267
 
240
268
  describe "#export_formats" do
241
- it "collects the unique export formats for the current response" do
242
- r = described_class.new({}, {})
269
+ before do
270
+ # rubocop:disable RSpec/SubjectStub
243
271
  allow(r).to receive_messages(documents: [double(export_formats: { a: 1, b: 2 }), double(export_formats: { b: 1, c: 2 })])
272
+ # rubocop:enable RSpec/SubjectStub
273
+ end
274
+
275
+ it "collects the unique export formats for the current response" do
244
276
  expect(r.export_formats).to include :a, :b
245
277
  end
246
278
  end