blacklight 8.0.0 → 8.1.0

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.github/workflows/ruby.yml +11 -0
  4. data/.rubocop.yml +4 -0
  5. data/.rubocop_todo.yml +67 -73
  6. data/VERSION +1 -1
  7. data/app/builders/blacklight/action_builder.rb +1 -1
  8. data/app/components/blacklight/advanced_search_form_component.html.erb +1 -1
  9. data/app/components/blacklight/advanced_search_form_component.rb +2 -2
  10. data/app/components/blacklight/document/sidebar_component.html.erb +1 -1
  11. data/app/components/blacklight/document/sidebar_component.rb +12 -0
  12. data/app/components/blacklight/response/pagination_component.html.erb +1 -1
  13. data/app/components/blacklight/response/pagination_component.rb +11 -2
  14. data/app/components/blacklight/search_bar_component.html.erb +1 -1
  15. data/app/controllers/concerns/blacklight/bookmarks.rb +1 -1
  16. data/app/helpers/blacklight/blacklight_helper_behavior.rb +10 -0
  17. data/app/models/concerns/blacklight/document/active_model_shim.rb +10 -0
  18. data/app/models/search.rb +6 -1
  19. data/app/services/blacklight/field_retriever.rb +13 -11
  20. data/app/views/catalog/_show_tools.html.erb +1 -0
  21. data/app/views/layouts/blacklight/base.html.erb +0 -3
  22. data/blacklight.gemspec +1 -2
  23. data/config/locales/blacklight.en.yml +1 -0
  24. data/lib/blacklight/component.rb +1 -1
  25. data/lib/blacklight/configuration.rb +10 -1
  26. data/lib/blacklight/engine.rb +12 -0
  27. data/lib/blacklight/solr/repository.rb +14 -2
  28. data/lib/blacklight/solr/search_builder_behavior.rb +2 -1
  29. data/lib/generators/blacklight/assets_generator.rb +1 -3
  30. data/lib/generators/blacklight/install_generator.rb +1 -3
  31. data/lib/generators/blacklight/templates/catalog_controller.rb +1 -0
  32. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +69 -0
  33. data/lib/railties/blacklight.rake +4 -4
  34. data/package.json +2 -2
  35. data/spec/components/blacklight/document/sidebar_component_spec.rb +63 -0
  36. data/spec/components/blacklight/facet_component_spec.rb +11 -1
  37. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +2 -2
  38. data/spec/components/blacklight/response/pagination_component_spec.rb +53 -0
  39. data/spec/components/blacklight/search_context/server_applied_params_component_spec.rb +11 -1
  40. data/spec/features/advanced_search_spec.rb +55 -0
  41. data/spec/features/axe_spec.rb +5 -0
  42. data/spec/helpers/blacklight_helper_spec.rb +10 -5
  43. data/spec/models/blacklight/configurable_spec.rb +1 -1
  44. data/spec/models/blacklight/solr/repository_spec.rb +27 -0
  45. data/spec/models/blacklight/solr/search_builder_spec.rb +8 -0
  46. data/spec/presenters/blacklight/show_presenter_spec.rb +4 -10
  47. data/spec/services/blacklight/field_retriever_spec.rb +17 -0
  48. data/spec/spec_helper.rb +29 -2
  49. data/spec/support/view_component_test_helpers.rb +14 -0
  50. data/spec/views/catalog/_paginate_compact.html.erb_spec.rb +2 -0
  51. metadata +11 -19
data/blacklight.gemspec CHANGED
@@ -31,14 +31,13 @@ Gem::Specification.new do |s|
31
31
  s.add_dependency "kaminari", ">= 0.15" # the pagination (page 1,2,3, etc..) of our search results
32
32
  s.add_dependency "i18n", '>= 1.7.0' # added named parameters
33
33
  s.add_dependency "ostruct", '>= 0.3.2'
34
- s.add_dependency "view_component", '>= 2.66', '< 3.1'
34
+ s.add_dependency "view_component", '>= 2.66', '< 4'
35
35
 
36
36
  s.add_development_dependency "rsolr", ">= 1.0.6", "< 3" # Library for interacting with rSolr.
37
37
  s.add_development_dependency "rspec-rails", "~> 6.0"
38
38
  s.add_development_dependency "rspec-collection_matchers", ">= 1.0"
39
39
  s.add_development_dependency 'axe-core-rspec'
40
40
  s.add_development_dependency "capybara", '~> 3'
41
- s.add_development_dependency 'webdrivers'
42
41
  s.add_development_dependency 'selenium-webdriver'
43
42
  s.add_development_dependency 'engine_cart', '~> 2.1'
44
43
  s.add_development_dependency "equivalent-xml"
@@ -244,6 +244,7 @@ en:
244
244
  more_options: More options
245
245
  any_of: 'Any of:'
246
246
  op:
247
+ label: search operator
247
248
  must: all
248
249
  should: any
249
250
  page_title: Advanced search - %{application_name}
@@ -47,7 +47,7 @@ module Blacklight
47
47
 
48
48
  component_class.sidecar_files(extensions).each_with_object([]) do |path, memo|
49
49
  pieces = File.basename(path).split(".")
50
- app_path = "#{Rails.root}/#{path.slice(path.index(component_class.view_component_path)..-1)}"
50
+ app_path = Rails.root.join(path.slice(path.index(component_class.view_component_path)..-1).to_s).to_s
51
51
 
52
52
  memo << {
53
53
  path: File.exist?(app_path) ? app_path : path,
@@ -87,6 +87,10 @@ module Blacklight
87
87
  # @since v5.2.0
88
88
  # @return [String] The url path (relative to the solr base url) to use when requesting only a single document
89
89
  property :document_solr_path, default: 'get'
90
+ # @!attribute json_solr_path
91
+ # @since v7.34.0
92
+ # @return [String] The url path (relative to the solr base url) to use when using Solr's JSON Query DSL (as with the advanced search)
93
+ property :json_solr_path, default: 'advanced'
90
94
  # @!attribute document_unique_id_param
91
95
  # @since v5.2.0
92
96
  # @return [Symbol] The solr query parameter used for sending the unique identifiers for one or more documents
@@ -171,7 +175,9 @@ module Blacklight
171
175
  # component class used to render the search bar
172
176
  search_bar_component: nil,
173
177
  # component class used to render the header above the documents
174
- search_header_component: Blacklight::SearchHeaderComponent
178
+ search_header_component: Blacklight::SearchHeaderComponent,
179
+ # pagination parameters to pass to kaminari
180
+ pagination_options: Blacklight::Engine.config.blacklight.default_pagination_options.dup
175
181
  )
176
182
 
177
183
  # @!attribute show
@@ -181,6 +187,9 @@ module Blacklight
181
187
  # document presenter class used by helpers and views
182
188
  document_presenter_class: nil,
183
189
  document_component: Blacklight::DocumentComponent,
190
+ # in Blacklight 9, the default show_tools_component configuration will
191
+ # be Blacklight::Document::ShowToolsComponent
192
+ show_tools_component: nil,
184
193
  sidebar_component: Blacklight::Document::SidebarComponent,
185
194
  display_type_field: nil,
186
195
  # the "field access" key to use to look up the document display fields
@@ -6,6 +6,18 @@ module Blacklight
6
6
  class Engine < Rails::Engine
7
7
  engine_name "blacklight"
8
8
 
9
+ config.before_configuration do
10
+ # see https://github.com/fxn/zeitwerk#for_gem
11
+ # Blacklight puts a generator into LOCAL APP lib/generators, so tell
12
+ # zeitwerk to ignore the whole directory? If we're using a recent
13
+ # enough version of Rails to have zeitwerk config
14
+ #
15
+ # See: https://github.com/cbeer/engine_cart/issues/117
16
+ if Rails.try(:autoloaders).try(:main).respond_to?(:ignore)
17
+ Rails.autoloaders.main.ignore(Rails.root.join('lib/generators'))
18
+ end
19
+ end
20
+
9
21
  config.after_initialize do
10
22
  Blacklight::Configuration.initialize_default_configuration
11
23
  end
@@ -21,7 +21,7 @@ module Blacklight::Solr
21
21
  # Execute a search query against solr
22
22
  # @param [Hash] params solr query parameters
23
23
  def search params = {}
24
- send_and_receive blacklight_config.solr_path, params.reverse_merge(qt: blacklight_config.qt)
24
+ send_and_receive search_path(params), params.reverse_merge(qt: blacklight_config.qt)
25
25
  end
26
26
 
27
27
  # @param [Hash] request_params
@@ -78,7 +78,7 @@ module Blacklight::Solr
78
78
  # @return [Hash]
79
79
  # @!visibility private
80
80
  def build_solr_request(solr_params)
81
- if solr_params[:json].present?
81
+ if uses_json_query_dsl?(solr_params)
82
82
  {
83
83
  data: { params: solr_params.to_hash.except(:json) }.merge(solr_params[:json]).to_json,
84
84
  method: :post,
@@ -122,5 +122,17 @@ module Blacklight::Solr
122
122
  []
123
123
  end
124
124
  end
125
+
126
+ # @return [String]
127
+ def search_path(solr_params)
128
+ return blacklight_config.json_solr_path if blacklight_config.json_solr_path && uses_json_query_dsl?(solr_params)
129
+
130
+ blacklight_config.solr_path
131
+ end
132
+
133
+ # @return [Boolean]
134
+ def uses_json_query_dsl?(solr_params)
135
+ solr_params[:json].present?
136
+ end
125
137
  end
126
138
  end
@@ -83,8 +83,9 @@ module Blacklight::Solr
83
83
  end
84
84
 
85
85
  def add_search_field_with_json_query_parameters(solr_parameters)
86
- bool_query = search_field.clause_params.transform_values { |v| v.merge(query: search_state.query_param) }
86
+ return unless search_state.query_param
87
87
 
88
+ bool_query = search_field.clause_params.transform_values { |v| v.merge(query: search_state.query_param) }
88
89
  solr_parameters.append_boolean_query(:must, bool_query)
89
90
  end
90
91
 
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'shellwords'
4
-
5
3
  module Blacklight
6
4
  class AssetsGenerator < Rails::Generators::Base
7
5
  class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.1'), desc: "Set the generated app's bootstrap version"
8
6
 
9
7
  def run_asset_pipeline_specific_generator
10
- generated_options = "--bootstrap-version='#{Shellwords.escape(options[:'bootstrap-version'])}'" if options[:'bootstrap-version']
8
+ generated_options = "--bootstrap-version='#{options[:'bootstrap-version']}'" if options[:'bootstrap-version']
11
9
 
12
10
  generator = if defined?(Propshaft)
13
11
  'blacklight:assets:propshaft'
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'shellwords'
4
-
5
3
  module Blacklight
6
4
  class Install < Rails::Generators::Base
7
5
  source_root File.expand_path('../templates', __FILE__)
@@ -37,7 +35,7 @@ module Blacklight
37
35
  # Call external generator in AssetsGenerator, so we can
38
36
  # leave that callable seperately too.
39
37
  def copy_public_assets
40
- generated_options = "--bootstrap-version='#{Shellwords.escape(options[:'bootstrap-version'])}'" if options[:'bootstrap-version']
38
+ generated_options = "--bootstrap-version='#{options[:'bootstrap-version']}'" if options[:'bootstrap-version']
41
39
 
42
40
  generate "blacklight:assets", generated_options unless options[:'skip-assets']
43
41
  end
@@ -38,6 +38,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
38
38
  # solr path which will be added to solr base url before the other solr params.
39
39
  #config.solr_path = 'select'
40
40
  #config.document_solr_path = 'get'
41
+ #config.json_solr_path = 'advanced'
41
42
 
42
43
  # items to show per page, each number in the array represent another option to choose from.
43
44
  #config.per_page = [10,20,50,100]
@@ -100,6 +100,75 @@
100
100
  </arr>
101
101
  </requestHandler>
102
102
 
103
+ <requestHandler name="/advanced" class="solr.SearchHandler">
104
+ <!-- a lucene request handler for using the JSON Query DSL,
105
+ specifically for advanced search.
106
+ Using a separate requestHandler is a workaround to
107
+ https://issues.apache.org/jira/browse/SOLR-16916, although
108
+ it could be desirable for other reasons as well.
109
+ -->
110
+ <lst name="defaults">
111
+ <str name="defType">lucene</str>
112
+ <str name="echoParams">explicit</str>
113
+ <str name="df">title_tsim</str>
114
+ <str name="qf">
115
+ id
116
+ full_title_tsim
117
+ short_title_tsim
118
+ alternative_title_tsim
119
+ active_fedora_model_ssi
120
+ title_tsim
121
+ author_tsim
122
+ subject_tsim
123
+ all_text_timv
124
+ </str>
125
+ <str name="pf">
126
+ all_text_timv^10
127
+ </str>
128
+
129
+ <str name="author_qf">
130
+ author_tsim
131
+ </str>
132
+ <str name="author_pf">
133
+ </str>
134
+ <str name="title_qf">
135
+ title_tsim
136
+ full_title_tsim
137
+ short_title_tsim
138
+ alternative_title_tsim
139
+ </str>
140
+ <str name="title_pf">
141
+ </str>
142
+ <str name="subject_qf">
143
+ subject_tsim
144
+ </str>
145
+ <str name="subject_pf">
146
+ </str>
147
+
148
+ <str name="fl">
149
+ *,
150
+ score
151
+ </str>
152
+
153
+ <str name="facet">true</str>
154
+ <str name="facet.mincount">1</str>
155
+ <str name="facet.limit">10</str>
156
+ <str name="facet.field">active_fedora_model_ssi</str>
157
+ <str name="facet.field">subject_ssim</str>
158
+
159
+ <str name="spellcheck">true</str>
160
+ <str name="spellcheck.dictionary">default</str>
161
+ <str name="spellcheck.onlyMorePopular">true</str>
162
+ <str name="spellcheck.extendedResults">true</str>
163
+ <str name="spellcheck.collate">false</str>
164
+ <str name="spellcheck.count">5</str>
165
+
166
+ </lst>
167
+ <arr name="last-components">
168
+ <str>spellcheck</str>
169
+ </arr>
170
+ </requestHandler>
171
+
103
172
  <requestHandler name="permissions" class="solr.SearchHandler" >
104
173
  <lst name="defaults">
105
174
  <str name="facet">off</str>
@@ -40,7 +40,7 @@ namespace :blacklight do
40
40
  exit 1
41
41
  end
42
42
  rescue => e
43
- puts e.to_s
43
+ puts e
44
44
  exit 1
45
45
  end
46
46
 
@@ -70,7 +70,7 @@ namespace :blacklight do
70
70
  end
71
71
  rescue => e
72
72
  errors += 1
73
- puts e.to_s
73
+ puts e
74
74
  end
75
75
 
76
76
  print " - search_results: "
@@ -92,7 +92,7 @@ namespace :blacklight do
92
92
  end
93
93
  rescue => e
94
94
  errors += 1
95
- puts e.to_s
95
+ puts e
96
96
  end
97
97
 
98
98
  print " - fetch: "
@@ -112,7 +112,7 @@ namespace :blacklight do
112
112
  end
113
113
  rescue => e
114
114
  errors += 1
115
- puts e.to_s
115
+ puts e
116
116
  end
117
117
 
118
118
  exit 1 if errors > 0
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "blacklight-frontend",
3
- "version": "8.0.0",
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)",
3
+ "version": "8.0.1",
4
+ "description": "The frontend code and styles for Blacklight",
5
5
  "main": "app/assets/javascripts/blacklight",
6
6
  "module": "app/assets/javascripts/blacklight/blacklight.esm.js",
7
7
  "scripts": {
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Blacklight::Document::SidebarComponent, type: :component do
6
+ subject(:component) { described_class.new(presenter: document) }
7
+
8
+ let(:view_context) { controller.view_context }
9
+ let(:render) do
10
+ component.render_in(view_context)
11
+ end
12
+
13
+ let(:rendered) do
14
+ Capybara::Node::Simple.new(render)
15
+ end
16
+
17
+ let(:document) { view_context.document_presenter(presented_document) }
18
+
19
+ let(:presented_document) { SolrDocument.new(id: 'x', title_tsim: 'Title') }
20
+
21
+ let(:blacklight_config) do
22
+ CatalogController.blacklight_config.deep_copy
23
+ end
24
+
25
+ let(:expected_html) { "<div class=\"expected-show_tools\">Expected Content</div>".html_safe }
26
+
27
+ before do
28
+ # Every call to view_context returns a different object. This ensures it stays stable.
29
+ allow(controller).to receive(:view_context).and_return(view_context)
30
+ allow(controller).to receive(:blacklight_config).and_return(blacklight_config)
31
+ end
32
+
33
+ describe '#render_show_tools' do
34
+ # rubocop:disable RSpec/SubjectStub
35
+ before do
36
+ allow(component).to receive(:render).with(an_instance_of(Blacklight::Document::MoreLikeThisComponent)).and_return("")
37
+ end
38
+
39
+ context "without a configured ShowTools component" do
40
+ before do
41
+ allow(component).to receive(:render).with('show_tools', document: presented_document, silence_deprecation: false).and_return(expected_html)
42
+ end
43
+
44
+ it 'renders show_tools partial' do
45
+ expect(rendered).to have_selector 'div[@class="expected-show_tools"]'
46
+ end
47
+ end
48
+
49
+ context "with a configured ShowTools component" do
50
+ let(:show_tools_component) { Class.new(Blacklight::Document::ShowToolsComponent) }
51
+
52
+ before do
53
+ blacklight_config.show.show_tools_component = show_tools_component
54
+ allow(component).to receive(:render).with(an_instance_of(show_tools_component)).and_return(expected_html)
55
+ end
56
+
57
+ it 'renders configured show_tools component' do
58
+ expect(rendered).to have_selector 'div[@class="expected-show_tools"]'
59
+ end
60
+ end
61
+ # rubocop:enable RSpec/SubjectStub
62
+ end
63
+ end
@@ -45,8 +45,18 @@ RSpec.describe Blacklight::FacetComponent, type: :component do
45
45
  Blacklight::Configuration::FacetField.new(key: 'field', partial: 'catalog/facet_partial').normalize!
46
46
  end
47
47
 
48
+ # Not sure why we need to re-implement rspec's stub_template, but
49
+ # we already were, and need a Rails 7.1+ safe alternate too
50
+ # https://github.com/rspec/rspec-rails/commit/4d65bea0619955acb15023b9c3f57a3a53183da8
51
+ # https://github.com/rspec/rspec-rails/issues/2696
48
52
  before do
49
- controller.view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for('catalog/_facet_partial.html.erb' => 'facet partial'))
53
+ replace_hash = { 'catalog/_facet_partial.html.erb' => 'facet partial' }
54
+
55
+ if ::Rails.version.to_f >= 7.1
56
+ controller.prepend_view_path(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
57
+ else
58
+ controller.view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
59
+ end
50
60
  end
51
61
 
52
62
  it 'renders the partial' do
@@ -35,13 +35,13 @@ RSpec.describe Blacklight::FacetItemPivotComponent, type: :component do
35
35
 
36
36
  it 'links to the facet and shows the number of hits' do
37
37
  expect(rendered).to have_selector 'li'
38
- expect(rendered).to have_link 'x', href: '/catalog?f%5Bz%5D=x'
38
+ expect(rendered).to have_link 'x', href: nokogiri_mediated_href(facet_item.href)
39
39
  expect(rendered).to have_selector '.facet-count', text: '10'
40
40
  end
41
41
 
42
42
  it 'has the facet hierarchy' do
43
43
  expect(rendered).to have_selector 'li ul.pivot-facet'
44
- expect(rendered).to have_link 'x:1', href: /f%5Bz%5D%5B%5D=x:1/
44
+ expect(rendered).to have_link 'x:1', href: nokogiri_mediated_href(facet_item.facet_item_presenters.first.href)
45
45
  end
46
46
 
47
47
  context 'with a selected facet' do
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Blacklight::Response::PaginationComponent, type: :component do
6
+ let(:render) do
7
+ with_request_url '/catalog?q=foo' do
8
+ render_inline(instance)
9
+ end
10
+ end
11
+
12
+ let(:instance) { described_class.new(response: response) }
13
+
14
+ context 'when there are many results' do
15
+ let(:response) { instance_double(Blacklight::Solr::Response, total: 10, current_page: 5, limit_value: 10_000, total_pages: 100) }
16
+
17
+ context 'with default config' do
18
+ before { render }
19
+
20
+ it "has links to deep pages" do
21
+ expect(page).not_to have_link '98'
22
+ expect(page).to have_link '99'
23
+ expect(page).to have_link '100'
24
+ expect(page).not_to have_link '101'
25
+ end
26
+ end
27
+
28
+ context 'when a different configuration that removes deep links is passed as a parameter' do
29
+ let(:instance) { described_class.new(response: response, left: 5, right: 0, outer_window: nil) }
30
+
31
+ before { render }
32
+
33
+ it "does not link to deep pages" do
34
+ expect(page).to have_link '1'
35
+ expect(page).not_to have_link '100'
36
+ end
37
+ end
38
+
39
+ context 'when a different configuration that removes deep links is configured in the controller' do
40
+ before do
41
+ allow(controller.blacklight_config.index)
42
+ .to receive(:pagination_options)
43
+ .and_return(theme: 'blacklight', left: 5, right: 0)
44
+ render
45
+ end
46
+
47
+ it "does not link to deep pages" do
48
+ expect(page).to have_link '1'
49
+ expect(page).not_to have_link '100'
50
+ end
51
+ end
52
+ end
53
+ end
@@ -10,7 +10,17 @@ RSpec.describe Blacklight::SearchContext::ServerAppliedParamsComponent, type: :c
10
10
  let(:view_context) { controller.view_context }
11
11
 
12
12
  before do
13
- view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for('application/_start_over.html.erb' => 'start over'))
13
+ # Not sure why we need to re-implement rspec's stub_template, but
14
+ # we already were, and need a Rails 7.1+ safe alternate too
15
+ # https://github.com/rspec/rspec-rails/commit/4d65bea0619955acb15023b9c3f57a3a53183da8
16
+ # https://github.com/rspec/rspec-rails/issues/2696
17
+ replace_hash = { 'application/_start_over.html.erb' => 'start over' }
18
+ if ::Rails.version.to_f >= 7.1
19
+ controller.prepend_view_path(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
20
+ else
21
+ view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
22
+ end
23
+
14
24
  allow(view_context).to receive(:current_search_session).and_return current_search_session
15
25
  allow(view_context).to receive(:link_back_to_catalog).with(any_args)
16
26
  end
@@ -5,9 +5,27 @@ require 'spec_helper'
5
5
  RSpec.describe "Blacklight Advanced Search Form" do
6
6
  describe "advanced search form" do
7
7
  before do
8
+ CatalogController.blacklight_config.search_fields['all_fields']['clause_params'] = {
9
+ edismax: {}
10
+ }
11
+ CatalogController.blacklight_config.search_fields['author']['clause_params'] = {
12
+ edismax: { qf: '${author_qf}' }
13
+ }
14
+ CatalogController.blacklight_config.search_fields['title']['clause_params'] = {
15
+ edismax: { qf: '${title_qf}' }
16
+ }
17
+ CatalogController.blacklight_config.search_fields['subject']['clause_params'] = {
18
+ edismax: { qf: '${subject_qf}' }
19
+ }
8
20
  visit '/catalog/advanced?hypothetical_existing_param=true&q=ignore+this+existing+query'
9
21
  end
10
22
 
23
+ after do
24
+ %w[all_fields author title subject].each do |field|
25
+ CatalogController.blacklight_config.search_fields[field].delete(:clause_params)
26
+ end
27
+ end
28
+
11
29
  it "has field and facet blocks" do
12
30
  expect(page).to have_selector('.query-criteria')
13
31
  expect(page).to have_selector('.limit-criteria')
@@ -45,6 +63,43 @@ RSpec.describe "Blacklight Advanced Search Form" do
45
63
  click_on 'advanced-search-submit'
46
64
  expect(page).to have_content 'Remove constraint Title: Medicine'
47
65
  expect(page).to have_content 'Strong Medicine speaks'
66
+ expect(page).to have_selector('article.document', count: 1)
67
+ end
68
+
69
+ it 'can limit to facets' do
70
+ fill_in 'Subject', with: 'Women'
71
+ click_on 'Language'
72
+ check 'Urdu 3'
73
+ click_on 'advanced-search-submit'
74
+ expect(page).to have_content 'Pākistānī ʻaurat dorāhe par'
75
+ expect(page).not_to have_content 'Ajikto kŭrŏk chŏrŏk sasimnikka : and 아직도 그럭 저럭 사십니까'
76
+ expect(page).to have_selector('article.document', count: 1)
77
+ end
78
+
79
+ it 'handles boolean queries' do
80
+ fill_in 'All Fields', with: 'history NOT strong'
81
+ click_on 'advanced-search-submit'
82
+ expect(page).to have_content('Ci an zhou bian')
83
+ expect(page).not_to have_content('Strong Medicine speaks')
84
+ expect(page).to have_selector('article.document', count: 10)
85
+ end
86
+
87
+ it 'handles queries in multiple fields with the ALL operator' do
88
+ fill_in 'All Fields', with: 'history'
89
+ fill_in 'Author', with: 'hearth'
90
+ click_on 'advanced-search-submit'
91
+ expect(page).to have_content('Strong Medicine speaks')
92
+ expect(page).to have_selector('article.document', count: 1)
93
+ end
94
+
95
+ it 'handles queries in multiple fields with the ANY operator' do
96
+ select 'any', from: 'op'
97
+ fill_in 'All Fields', with: 'history'
98
+ fill_in 'Subject', with: 'women'
99
+ click_on 'advanced-search-submit'
100
+ expect(page).to have_content('Ci an zhou bian')
101
+ expect(page).to have_content('Pākistānī ʻaurat dorāhe par')
102
+ expect(page).to have_selector('article.document', count: 10)
48
103
  end
49
104
  end
50
105
 
@@ -21,6 +21,11 @@ RSpec.describe 'Accessibility testing', api: false, js: true do
21
21
  expect(page).to be_accessible
22
22
  end
23
23
 
24
+ it 'validates the advanced search form' do
25
+ visit advanced_search_catalog_path
26
+ expect(page).to be_accessible
27
+ end
28
+
24
29
  it 'validates the single results page' do
25
30
  visit solr_document_path('2007020969')
26
31
  expect(page).to be_accessible
@@ -185,12 +185,17 @@ RSpec.describe BlacklightHelper do
185
185
  blacklight_config.view.gallery(template: '/my/partial')
186
186
  end
187
187
 
188
- def stub_template(hash)
189
- view.view_paths.unshift(ActionView::FixtureResolver.new(hash))
190
- end
191
-
192
188
  it 'renders that template' do
193
- stub_template 'my/_partial.html.erb' => 'some content'
189
+ # Not sure why we need to re-implement rspec's stub_template, but
190
+ # we already were, and need a Rails 7.1+ safe alternate too
191
+ # https://github.com/rspec/rspec-rails/commit/4d65bea0619955acb15023b9c3f57a3a53183da8
192
+ # https://github.com/rspec/rspec-rails/issues/2696
193
+ replace_hash = { 'my/_partial.html.erb' => 'some content' }
194
+ if ::Rails.version.to_f >= 7.1
195
+ controller.prepend_view_path(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
196
+ else
197
+ view.view_paths.unshift(ActionView::FixtureResolver.new(replace_hash))
198
+ end
194
199
 
195
200
  response = helper.render_document_index_with_view :gallery, [obj1, obj1]
196
201
 
@@ -93,7 +93,7 @@ RSpec.describe "Blacklight::Configurable", api: true do
93
93
  instance.blacklight_config.bar << "123"
94
94
  expect(instance.blacklight_config).not_to eq klass.blacklight_config
95
95
  expect(klass.blacklight_config.foo).to eq "bar"
96
- expect(instance.blacklight_config.foo).to eq "bar"
96
+ expect(instance.blacklight_config.foo).to eq "bar"
97
97
  expect(klass.blacklight_config.bar).not_to include("123")
98
98
  expect(instance.blacklight_config.bar).to include("asd", "123")
99
99
  end
@@ -153,6 +153,33 @@ RSpec.describe Blacklight::Solr::Repository, api: true do
153
153
  expect(JSON.parse(actual_params[:data]).with_indifferent_access).to include(query: { bool: {} })
154
154
  expect(actual_params[:headers]).to include({ 'Content-Type' => 'application/json' })
155
155
  end
156
+
157
+ context "without a json solr path configured" do
158
+ before do
159
+ blacklight_config.json_solr_path = nil
160
+ end
161
+
162
+ it "uses the default solr path" do
163
+ blacklight_config.solr_path = 'xyz'
164
+ allow(subject.connection).to receive(:send_and_receive) do |path|
165
+ expect(path).to eq 'xyz'
166
+ end
167
+ subject.search(input_params)
168
+ end
169
+ end
170
+
171
+ context "with a json solr path configured" do
172
+ before do
173
+ blacklight_config.json_solr_path = 'my-great-json'
174
+ end
175
+
176
+ it "uses the configured json_solr_path" do
177
+ allow(subject.connection).to receive(:send_and_receive) do |path|
178
+ expect(path).to eq 'my-great-json'
179
+ end
180
+ subject.search(input_params)
181
+ end
182
+ end
156
183
  end
157
184
  end
158
185
 
@@ -406,6 +406,14 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, api: true do
406
406
  it 'includes addtional clause parameters for the field' do
407
407
  expect(subject.dig(:json, :query, :bool, :must, 0, :edismax)).to include another: :parameter
408
408
  end
409
+
410
+ context 'with an empty search' do
411
+ let(:subject_search_params) { { commit: "search", search_field: "subject", action: "index", controller: "catalog", rows: "10", q: nil } }
412
+
413
+ it 'does not add nil query value clauses to json query' do
414
+ expect(subject).not_to have_key :json
415
+ end
416
+ end
409
417
  end
410
418
 
411
419
  describe "sorting" do