blacklight 7.33.1 → 7.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -0
  3. data/.github/workflows/ruby.yml +21 -1
  4. data/.rubocop.yml +2 -0
  5. data/Gemfile +4 -0
  6. data/VERSION +1 -1
  7. data/app/components/blacklight/advanced_search_form_component.html.erb +1 -1
  8. data/app/components/blacklight/advanced_search_form_component.rb +5 -5
  9. data/app/components/blacklight/content_areas_shim.rb +1 -1
  10. data/app/components/blacklight/document/action_component.html.erb +2 -9
  11. data/app/components/blacklight/document/action_component.rb +18 -0
  12. data/app/components/blacklight/document/actions_component.rb +1 -1
  13. data/app/components/blacklight/document_component.rb +33 -10
  14. data/app/components/blacklight/document_metadata_component.html.erb +4 -2
  15. data/app/components/blacklight/document_metadata_component.rb +6 -2
  16. data/app/components/blacklight/facet_field_checkboxes_component.html.erb +2 -2
  17. data/app/components/blacklight/facet_field_list_component.html.erb +2 -2
  18. data/app/components/blacklight/header_component.html.erb +2 -0
  19. data/app/components/blacklight/header_component.rb +26 -0
  20. data/app/components/blacklight/metadata_field_component.html.erb +2 -2
  21. data/app/components/blacklight/metadata_field_layout_component.rb +7 -4
  22. data/app/components/blacklight/response/pagination_component.html.erb +1 -1
  23. data/app/components/blacklight/response/pagination_component.rb +5 -1
  24. data/app/components/blacklight/response/view_type_component.rb +1 -1
  25. data/app/components/blacklight/search_navbar_component.html.erb +5 -0
  26. data/app/components/blacklight/search_navbar_component.rb +34 -0
  27. data/app/components/blacklight/system/dropdown_component.rb +2 -2
  28. data/app/components/blacklight/system/flash_message_component.rb +1 -1
  29. data/app/components/blacklight/top_navbar_component.html.erb +12 -0
  30. data/app/components/blacklight/top_navbar_component.rb +17 -0
  31. data/app/controllers/concerns/blacklight/base.rb +5 -0
  32. data/app/controllers/concerns/blacklight/bookmarks.rb +5 -1
  33. data/app/controllers/concerns/blacklight/catalog.rb +14 -3
  34. data/app/controllers/concerns/blacklight/controller.rb +3 -2
  35. data/app/helpers/blacklight/blacklight_helper_behavior.rb +2 -2
  36. data/app/helpers/blacklight/render_partials_helper_behavior.rb +1 -0
  37. data/app/models/concerns/blacklight/document/active_model_shim.rb +10 -0
  38. data/app/models/concerns/blacklight/document/attributes.rb +50 -0
  39. data/app/models/concerns/blacklight/document.rb +12 -20
  40. data/app/models/search.rb +6 -1
  41. data/app/presenters/blacklight/rendering/join.rb +1 -1
  42. data/app/services/blacklight/field_retriever.rb +13 -11
  43. data/app/values/blacklight/types.rb +99 -11
  44. data/app/views/catalog/_document.html.erb +1 -1
  45. data/app/views/catalog/_facet_layout.html.erb +2 -2
  46. data/app/views/catalog/_search_form.html.erb +1 -1
  47. data/app/views/catalog/_show_main_content.html.erb +2 -2
  48. data/app/views/catalog/_show_sidebar.html.erb +1 -1
  49. data/app/views/catalog/_show_tools.html.erb +4 -3
  50. data/app/views/catalog/facet.html.erb +3 -3
  51. data/app/views/layouts/blacklight/base.html.erb +7 -7
  52. data/app/views/shared/_header_navbar.html.erb +1 -22
  53. data/blacklight.gemspec +3 -4
  54. data/config/locales/blacklight.en.yml +1 -0
  55. data/docker-compose.yml +1 -0
  56. data/lib/blacklight/configuration.rb +39 -2
  57. data/lib/blacklight/engine.rb +15 -0
  58. data/lib/blacklight/solr/repository.rb +14 -2
  59. data/lib/blacklight/solr/request.rb +2 -0
  60. data/lib/blacklight/solr/search_builder_behavior.rb +2 -1
  61. data/lib/blacklight.rb +1 -1
  62. data/lib/generators/blacklight/assets_generator.rb +1 -1
  63. data/lib/generators/blacklight/install_generator.rb +1 -1
  64. data/lib/generators/blacklight/templates/catalog_controller.rb +4 -0
  65. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +69 -0
  66. data/lib/generators/blacklight/templates/solr_document.rb +1 -1
  67. data/lib/railties/blacklight.rake +4 -4
  68. data/package.json +1 -1
  69. data/spec/components/blacklight/document_component_spec.rb +60 -11
  70. data/spec/components/blacklight/facet_component_spec.rb +11 -1
  71. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +3 -2
  72. data/spec/components/blacklight/header_component_spec.rb +20 -0
  73. data/spec/components/blacklight/search_bar_component_spec.rb +1 -1
  74. data/spec/controllers/blacklight/base_spec.rb +1 -1
  75. data/spec/features/advanced_search_spec.rb +56 -0
  76. data/spec/features/axe_spec.rb +5 -0
  77. data/spec/features/sitelinks_search_box_spec.rb +13 -0
  78. data/spec/helpers/blacklight/search_history_constraints_helper_behavior_spec.rb +8 -15
  79. data/spec/helpers/blacklight_helper_spec.rb +10 -5
  80. data/spec/models/blacklight/configuration_spec.rb +22 -0
  81. data/spec/models/blacklight/solr/repository_spec.rb +27 -0
  82. data/spec/models/blacklight/solr/search_builder_spec.rb +16 -0
  83. data/spec/models/solr_document_spec.rb +21 -3
  84. data/spec/presenters/blacklight/show_presenter_spec.rb +4 -10
  85. data/spec/services/blacklight/field_retriever_spec.rb +17 -0
  86. data/spec/spec_helper.rb +32 -5
  87. data/spec/support/view_component_test_helpers.rb +35 -0
  88. data/spec/views/catalog/_show_tools.html.erb_spec.rb +24 -10
  89. metadata +30 -27
  90. data/spec/features/sitelinks_search_box.rb +0 -13
  91. data/spec/support/view_component_capybara_test_helpers.rb +0 -8
@@ -18,6 +18,8 @@ class Blacklight::Solr::Request < ActiveSupport::HashWithIndifferentAccess
18
18
  end
19
19
 
20
20
  def append_query(query)
21
+ return if query.nil?
22
+
21
23
  if self['q'] || dig(:json, :query, :bool)
22
24
  self[:json] ||= { query: { bool: { must: [] } } }
23
25
  self[:json][:query] ||= { bool: { must: [] } }
@@ -102,8 +102,9 @@ module Blacklight::Solr
102
102
  end
103
103
 
104
104
  def add_search_field_with_json_query_parameters(solr_parameters)
105
- bool_query = search_field.clause_params.transform_values { |v| v.merge(query: search_state.query_param) }
105
+ return unless search_state.query_param
106
106
 
107
+ bool_query = search_field.clause_params.transform_values { |v| v.merge(query: search_state.query_param) }
107
108
  solr_parameters.append_boolean_query(:must, bool_query)
108
109
  end
109
110
 
data/lib/blacklight.rb CHANGED
@@ -23,7 +23,7 @@ module Blacklight
23
23
  require 'blacklight/engine' if defined?(Rails)
24
24
 
25
25
  def self.blacklight_config_file
26
- "#{::Rails.root}/config/blacklight.yml"
26
+ Rails.root.join("config/blacklight.yml")
27
27
  end
28
28
 
29
29
  ##
@@ -37,7 +37,7 @@ module Blacklight
37
37
  def appease_sprockets4
38
38
  return if !defined?(Sprockets::VERSION) || Sprockets::VERSION < '4' || using_importmap?
39
39
 
40
- append_to_file 'app/assets/config/manifest.js', "\n//= link application.js"
40
+ append_to_file 'app/assets/config/manifest.js', "\n//= link application.js\n"
41
41
  empty_directory 'app/assets/images'
42
42
  end
43
43
 
@@ -34,7 +34,7 @@ module Blacklight
34
34
  # Call external generator in AssetsGenerator, so we can
35
35
  # leave that callable seperately too.
36
36
  def copy_public_assets
37
- generated_options = "--bootstrap-version #{options[:'bootstrap-version']}" if options[:'bootstrap-version']
37
+ generated_options = "--bootstrap-version='#{options[:'bootstrap-version']}'" if options[:'bootstrap-version']
38
38
 
39
39
  generate "blacklight:assets", generated_options unless options[:'skip-assets']
40
40
  end
@@ -15,6 +15,9 @@ class <%= controller_name.classify %>Controller < ApplicationController
15
15
  ## Model that maps search index responses to the blacklight response model
16
16
  # config.response_model = Blacklight::Solr::Response
17
17
  #
18
+ ## The destination for the link around the logo in the header
19
+ # config.logo_link = root_path
20
+ #
18
21
  ## Should the raw solr document endpoint (e.g. /catalog/:id/raw) be enabled
19
22
  # config.raw_endpoint.enabled = false
20
23
 
@@ -26,6 +29,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
26
29
  # solr path which will be added to solr base url before the other solr params.
27
30
  #config.solr_path = 'select'
28
31
  #config.document_solr_path = 'get'
32
+ #config.json_solr_path = 'advanced'
29
33
 
30
34
  # items to show per page, each number in the array represent another option to choose from.
31
35
  #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>
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Represent a single document returned from Solr
3
+ # Represents a single document returned from Solr
4
4
  class <%= model_name.classify %>
5
5
  include Blacklight::Solr::Document
6
6
 
@@ -41,7 +41,7 @@ namespace :blacklight do
41
41
  exit 1
42
42
  end
43
43
  rescue => e
44
- puts e.to_s
44
+ puts e
45
45
  exit 1
46
46
  end
47
47
 
@@ -71,7 +71,7 @@ namespace :blacklight do
71
71
  end
72
72
  rescue => e
73
73
  errors += 1
74
- puts e.to_s
74
+ puts e
75
75
  end
76
76
 
77
77
  print " - search_results: "
@@ -93,7 +93,7 @@ namespace :blacklight do
93
93
  end
94
94
  rescue => e
95
95
  errors += 1
96
- puts e.to_s
96
+ puts e
97
97
  end
98
98
 
99
99
  print " - fetch: "
@@ -113,7 +113,7 @@ namespace :blacklight do
113
113
  end
114
114
  rescue => e
115
115
  errors += 1
116
- puts e.to_s
116
+ puts e
117
117
  end
118
118
 
119
119
  exit 1 if errors > 0
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "blacklight-frontend",
3
3
  "version": "7.33.1",
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)",
4
+ "description": "The frontend code and styles for Blacklight",
5
5
  "main": "app/assets/javascripts/blacklight",
6
6
  "scripts": {
7
7
  "js-compile-bundle": "shx cat app/javascript/blacklight/core.js app/javascript/blacklight/autocomplete.js app/javascript/blacklight/bookmark_toggle.js app/javascript/blacklight/button_focus.js app/javascript/blacklight/checkbox_submit.js app/javascript/blacklight/facet_load.js app/javascript/blacklight/modal.js app/javascript/blacklight/search_context.js | shx sed \"s/^(import|export).*//\" | babel --filename app/javascript/blacklight/blacklight.js > app/assets/javascripts/blacklight/blacklight.js"
@@ -74,6 +74,10 @@ RSpec.describe Blacklight::DocumentComponent, type: :component do
74
74
  end
75
75
 
76
76
  context 'index view' do
77
+ before do
78
+ controller.action_name = "index"
79
+ end
80
+
77
81
  let(:attr) { { counter: 5 } }
78
82
 
79
83
  it 'has data properties' do
@@ -92,9 +96,12 @@ RSpec.describe Blacklight::DocumentComponent, type: :component do
92
96
  end
93
97
 
94
98
  context 'with a document rendered as part of a collection' do
95
- let(:attr) { { document_counter: 10, counter_offset: 100 } }
99
+ # ViewComponent 3 changes iteration counters to begin at 0 rather than 1
100
+ let(:document_counter) { ViewComponent::VERSION::MAJOR < 3 ? 11 : 10 }
101
+ let(:attr) { { document_counter: document_counter, counter_offset: 100 } }
96
102
 
97
103
  it 'renders a counter with the title' do
104
+ # after ViewComponent 2.5, collection counter params are 1-indexed
98
105
  expect(rendered).to have_selector 'header', text: '111. Title'
99
106
  end
100
107
  end
@@ -106,13 +113,22 @@ RSpec.describe Blacklight::DocumentComponent, type: :component do
106
113
  it 'renders a thumbnail' do
107
114
  expect(rendered).to have_selector 'a[href="/catalog/x"] img[src="http://example.com/image.jpg"]'
108
115
  end
116
+
117
+ context 'with default metadata component' do
118
+ it 'renders metadata' do
119
+ expect(rendered).to have_selector 'dl.document-metadata'
120
+ expect(rendered).to have_selector 'dt', text: 'Title:'
121
+ expect(rendered).to have_selector 'dd', text: 'Title'
122
+ expect(rendered).not_to have_selector 'dt', text: 'ISBN:'
123
+ end
124
+ end
109
125
  end
110
126
 
111
127
  context 'show view' do
112
128
  let(:attr) { { title_component: :h1, show: true } }
113
129
 
114
130
  before do
115
- allow(view_context).to receive(:action_name).and_return('show')
131
+ controller.action_name = "show"
116
132
  end
117
133
 
118
134
  it 'renders with an id' do
@@ -143,13 +159,46 @@ RSpec.describe Blacklight::DocumentComponent, type: :component do
143
159
  blacklight_config.show.embed_component = StubComponent
144
160
  expect(rendered).to have_content 'embed'
145
161
  end
146
- end
147
162
 
148
- it 'renders metadata' do
149
- expect(rendered).to have_selector 'dl.document-metadata'
150
- expect(rendered).to have_selector 'dt', text: 'Title:'
151
- expect(rendered).to have_selector 'dd', text: 'Title'
152
- expect(rendered).not_to have_selector 'dt', text: 'ISBN:'
163
+ context 'with configured metadata component' do
164
+ let(:custom_component_class) do
165
+ Class.new(Blacklight::DocumentMetadataComponent) do
166
+ # Override component rendering with our own value
167
+ def call
168
+ 'blah'
169
+ end
170
+ end
171
+ end
172
+
173
+ before do
174
+ stub_const('MyMetadataComponent', custom_component_class)
175
+ blacklight_config.show.metadata_component = MyMetadataComponent
176
+ end
177
+
178
+ it 'renders custom component' do
179
+ expect(rendered).to have_text 'blah'
180
+ end
181
+ end
182
+
183
+ context 'with configured title component' do
184
+ let(:custom_component_class) do
185
+ Class.new(Blacklight::DocumentTitleComponent) do
186
+ # Override component rendering with our own value
187
+ def call
188
+ 'Titleriffic'
189
+ end
190
+ end
191
+ end
192
+
193
+ before do
194
+ stub_const('MyTitleComponent', custom_component_class)
195
+ blacklight_config.show.title_component = MyTitleComponent
196
+ end
197
+
198
+ it 'renders custom component' do
199
+ expect(rendered).to have_text 'Titleriffic'
200
+ end
201
+ end
153
202
  end
154
203
 
155
204
  context 'with a thumbnail component' do
@@ -167,11 +216,11 @@ RSpec.describe Blacklight::DocumentComponent, type: :component do
167
216
  end
168
217
  end
169
218
 
170
- context 'with before_title' do
219
+ context 'with before_titles' do
171
220
  let(:render) do
172
221
  component.render_in(view_context) do
173
- component.title do |c|
174
- c.before_title { 'Prefix!' }
222
+ component.with_title do |c|
223
+ c.with_before_title { 'Prefix!' }
175
224
  end
176
225
  end
177
226
  end
@@ -51,7 +51,17 @@ RSpec.describe Blacklight::FacetComponent, type: :component do
51
51
  end
52
52
 
53
53
  before do
54
- controller.view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for('catalog/_facet_partial.html.erb' => 'facet partial'))
54
+ # Not sure why we need to re-implement rspec's stub_template, but
55
+ # we already were, and need a Rails 7.1+ safe alternate too
56
+ # https://github.com/rspec/rspec-rails/commit/4d65bea0619955acb15023b9c3f57a3a53183da8
57
+ # https://github.com/rspec/rspec-rails/issues/2696
58
+
59
+ replace_hash = { 'catalog/_facet_partial.html.erb' => 'facet partial' }
60
+ if ::Rails.version.to_f >= 7.1
61
+ controller.prepend_view_path(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
62
+ else
63
+ controller.view_context.view_paths.unshift(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
64
+ end
55
65
  end
56
66
 
57
67
  it 'renders the partial' do
@@ -33,13 +33,14 @@ RSpec.describe Blacklight::FacetItemPivotComponent, type: :component do
33
33
 
34
34
  it 'links to the facet and shows the number of hits' do
35
35
  expect(rendered).to have_selector 'li'
36
- expect(rendered).to have_link 'x', href: '/catalog?f%5Bz%5D=x'
36
+ expect(rendered).to have_link 'x', href: nokogiri_mediated_href(facet_item.href)
37
37
  expect(rendered).to have_selector '.facet-count', text: '10'
38
38
  end
39
39
 
40
40
  it 'has the facet hierarchy' do
41
+ pending
41
42
  expect(rendered).to have_selector 'li ul.pivot-facet'
42
- expect(rendered).to have_link 'x:1', href: /f%5Bz%5D%5B%5D=x%3A1/
43
+ expect(rendered).to have_link 'x:1', href: nokogiri_mediated_href(facet_item.facet_item_presenters.first.href)
43
44
  end
44
45
 
45
46
  context 'with a selected facet' do
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Blacklight::HeaderComponent, type: :component do
4
+ before do
5
+ with_controller_class(CatalogController) do
6
+ allow(controller).to receive(:current_user).and_return(nil)
7
+ allow(controller).to receive(:search_action_url).and_return('/search')
8
+ render
9
+ end
10
+ end
11
+
12
+ context 'with no slots' do
13
+ let(:render) { render_inline(described_class.new(blacklight_config: CatalogController.blacklight_config)) }
14
+
15
+ it 'draws the topbar' do
16
+ expect(page).to have_css 'nav.topbar'
17
+ expect(page).to have_link 'Blacklight', href: '/'
18
+ end
19
+ end
20
+ end
@@ -29,7 +29,7 @@ RSpec.describe Blacklight::SearchBarComponent, type: :component do
29
29
  context 'when a button is passed in' do
30
30
  subject(:render) do
31
31
  render_inline(instance) do |c|
32
- c.search_button do
32
+ c.with_search_button do
33
33
  controller.view_context.tag.button "hello", id: 'custom_search'
34
34
  end
35
35
  end
@@ -3,7 +3,7 @@
3
3
  RSpec.describe Blacklight::Base do
4
4
  subject { controller }
5
5
 
6
- let(:controller) { (Class.new(ApplicationController) { include Blacklight::Base }).new }
6
+ let(:controller) { Deprecation.silence(described_class) { (Class.new(ApplicationController) { include Blacklight::Base }).new } }
7
7
 
8
8
  describe "#search_state" do
9
9
  subject { controller.send(:search_state) }
@@ -5,9 +5,28 @@ 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
+ }
20
+ CatalogController.blacklight_config.json_solr_path = 'advanced'
8
21
  visit '/catalog/advanced?hypothetical_existing_param=true&q=ignore+this+existing+query'
9
22
  end
10
23
 
24
+ after do
25
+ %w[all_fields author title subject].each do |field|
26
+ CatalogController.blacklight_config.search_fields[field].delete(:clause_params)
27
+ end
28
+ end
29
+
11
30
  it "has field and facet blocks" do
12
31
  expect(page).to have_selector('.query-criteria')
13
32
  expect(page).to have_selector('.limit-criteria')
@@ -45,6 +64,43 @@ RSpec.describe "Blacklight Advanced Search Form" do
45
64
  click_on 'advanced-search-submit'
46
65
  expect(page).to have_content 'Remove constraint Title: Medicine'
47
66
  expect(page).to have_content 'Strong Medicine speaks'
67
+ expect(page).to have_selector('article.document', count: 1)
68
+ end
69
+
70
+ it 'can limit to facets' do
71
+ fill_in 'Subject', with: 'Women'
72
+ click_on 'Language'
73
+ check 'Urdu 3'
74
+ click_on 'advanced-search-submit'
75
+ expect(page).to have_content 'Pākistānī ʻaurat dorāhe par'
76
+ expect(page).not_to have_content 'Ajikto kŭrŏk chŏrŏk sasimnikka : and 아직도 그럭 저럭 사십니까'
77
+ expect(page).to have_selector('article.document', count: 1)
78
+ end
79
+
80
+ it 'handles boolean queries' do
81
+ fill_in 'All Fields', with: 'history NOT strong'
82
+ click_on 'advanced-search-submit'
83
+ expect(page).to have_content('Ci an zhou bian')
84
+ expect(page).not_to have_content('Strong Medicine speaks')
85
+ expect(page).to have_selector('article.document', count: 10)
86
+ end
87
+
88
+ it 'handles queries in multiple fields with the ALL operator' do
89
+ fill_in 'All Fields', with: 'history'
90
+ fill_in 'Author', with: 'hearth'
91
+ click_on 'advanced-search-submit'
92
+ expect(page).to have_content('Strong Medicine speaks')
93
+ expect(page).to have_selector('article.document', count: 1)
94
+ end
95
+
96
+ it 'handles queries in multiple fields with the ANY operator' do
97
+ select 'any', from: 'op'
98
+ fill_in 'All Fields', with: 'history'
99
+ fill_in 'Subject', with: 'women'
100
+ click_on 'advanced-search-submit'
101
+ expect(page).to have_content('Ci an zhou bian')
102
+ expect(page).to have_content('Pākistānī ʻaurat dorāhe par')
103
+ expect(page).to have_selector('article.document', count: 10)
48
104
  end
49
105
  end
50
106
 
@@ -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.excluding('.search-query-form')
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
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe 'Sitelinks search box' do
4
+ it 'is home page' do
5
+ visit root_path
6
+ expect(page).to have_selector 'script[type="application/ld+json"]', visible: :hidden
7
+ end
8
+
9
+ it 'on search page' do
10
+ visit search_catalog_path q: 'book'
11
+ expect(page).not_to have_selector 'script[type="application/ld+json"]', visible: :hidden
12
+ end
13
+ end
@@ -25,8 +25,8 @@ RSpec.describe Blacklight::SearchHistoryConstraintsHelperBehavior do
25
25
  it "renders basic element" do
26
26
  response = helper.render_search_to_s_element("key", "value")
27
27
  expect(response).to have_selector("span.constraint") do |span|
28
- expect(span).to have_selector("span.filter-name", content: "key:")
29
- expect(span).to have_selector("span.filter-value", content: "value")
28
+ expect(span).to have_selector("span.filter-name", text: "key:")
29
+ expect(span).to have_selector("span.filter-values", text: "value")
30
30
  end
31
31
  expect(response).to be_html_safe
32
32
  end
@@ -34,24 +34,17 @@ RSpec.describe Blacklight::SearchHistoryConstraintsHelperBehavior do
34
34
  it "escapes them that need escaping" do
35
35
  response = helper.render_search_to_s_element("key>", "value>")
36
36
  expect(response).to have_selector("span.constraint") do |span|
37
- expect(span).to have_selector("span.filter-name") do |s2|
38
- # Note: nokogiri's gettext will unescape the inner html
39
- # which seems to be what rspecs "contains" method calls on
40
- # text nodes - thus the to_s inserted below.
41
- expect(s2).to match(/key&gt;:/)
42
- end
43
- expect(span).to have_selector("span.filter-value") do |s3|
44
- expect(s3).to match(/value&gt;/)
45
- end
37
+ expect(span).to have_selector("span.filter-name", text: 'key>:')
38
+ expect(span).to have_selector("span.filter-values", text: 'value>')
46
39
  end
47
40
  expect(response).to be_html_safe
48
41
  end
49
42
 
50
- it "does not escape with options set thus" do
51
- response = helper.render_search_to_s_element("key>", "value>", escape_key: false, escape_value: false)
43
+ xit "does not escape with options set thus" do
44
+ response = helper.render_search_to_s_element("<key>", "value>", escape_key: false, escape_value: false)
52
45
  expect(response).to have_selector("span.constraint") do |span|
53
- expect(span).to have_selector("span.filter-name", content: "key>:")
54
- expect(span).to have_selector("span.filter-value", content: "value>")
46
+ expect(span).to have_selector("span.filter-name", text: "key>:")
47
+ expect(span).to have_selector("span.filter-values", text: "value>")
55
48
  end
56
49
  expect(response).to be_html_safe
57
50
  end
@@ -331,12 +331,17 @@ RSpec.describe BlacklightHelper do
331
331
  blacklight_config.view.gallery(template: '/my/partial')
332
332
  end
333
333
 
334
- def stub_template(hash)
335
- view.view_paths.unshift(ActionView::FixtureResolver.new(hash))
336
- end
337
-
338
334
  it 'renders that template' do
339
- stub_template 'my/_partial.html.erb' => 'some content'
335
+ # Not sure why we need to re-implement rspec's stub_template, but
336
+ # we already were, and need a Rails 7.1+ safe alternate too
337
+ # https://github.com/rspec/rspec-rails/commit/4d65bea0619955acb15023b9c3f57a3a53183da8
338
+ # https://github.com/rspec/rspec-rails/issues/2696
339
+ replace_hash = { 'my/_partial.html.erb' => 'some content' }
340
+ if ::Rails.version.to_f >= 7.1
341
+ controller.prepend_view_path(RSpec::Rails::ViewExampleGroup::StubResolverCache.resolver_for(replace_hash))
342
+ else
343
+ view.view_paths.unshift(ActionView::FixtureResolver.new(replace_hash))
344
+ end
340
345
 
341
346
  response = helper.render_document_index_with_view :gallery, [obj1, obj1]
342
347
 
@@ -723,4 +723,26 @@ RSpec.describe "Blacklight::Configuration", api: true do
723
723
  expect { config.view.a = '123' }.to raise_error(FrozenError)
724
724
  end
725
725
  end
726
+
727
+ describe '.default_configuration' do
728
+ it 'adds additional default configuration properties' do
729
+ Blacklight::Configuration.default_configuration do
730
+ Blacklight::Configuration.default_values[:a] = '123'
731
+ end
732
+
733
+ Blacklight::Configuration.default_configuration do
734
+ Blacklight::Configuration.default_values[:b] = 'abc'
735
+ end
736
+
737
+ expect(Blacklight::Configuration.default_values[:a]).to eq '123'
738
+ expect(Blacklight::Configuration.default_values[:b]).to eq 'abc'
739
+ ensure
740
+ # reset the default configuration
741
+ Blacklight::Configuration.default_values.delete(:a)
742
+ Blacklight::Configuration.default_values.delete(:b)
743
+
744
+ Blacklight::Configuration.default_configuration.delete_at(1)
745
+ Blacklight::Configuration.default_configuration.delete_at(2)
746
+ end
747
+ end
726
748
  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
 
@@ -191,6 +191,14 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, api: true do
191
191
  end
192
192
  end
193
193
 
194
+ describe "for a missing string search" do
195
+ let(:user_params) { { q: nil } }
196
+
197
+ it "does not populate the q parameter in solr parameters" do
198
+ expect(subject).not_to have_key :q
199
+ end
200
+ end
201
+
194
202
  describe "for an empty string search" do
195
203
  let(:user_params) { { q: "" } }
196
204
 
@@ -398,6 +406,14 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, api: true do
398
406
  it 'includes addtional clause parameters for the field' do
399
407
  expect(subject.dig(:json, :query, :bool, :must, 0, :edismax)).to include another: :parameter
400
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
401
417
  end
402
418
 
403
419
  describe "overriding of qt parameter" do