blacklight 7.13.0 → 7.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +109 -0
  3. data/README.md +0 -2
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/blacklight/blacklight.js +4 -2
  6. data/app/assets/stylesheets/blacklight/_header.scss +0 -5
  7. data/app/assets/stylesheets/blacklight/blacklight_defaults.scss +0 -1
  8. data/app/components/blacklight/advanced_search_form_component.html.erb +46 -0
  9. data/app/components/blacklight/advanced_search_form_component.rb +75 -0
  10. data/app/components/blacklight/constraint_component.html.erb +1 -1
  11. data/app/components/blacklight/constraints_component.rb +42 -17
  12. data/app/components/blacklight/document/thumbnail_component.html.erb +2 -2
  13. data/app/components/blacklight/document/thumbnail_component.rb +5 -2
  14. data/app/components/blacklight/document_component.rb +7 -2
  15. data/app/components/blacklight/document_metadata_component.rb +1 -1
  16. data/app/components/blacklight/facet_field_checkboxes_component.html.erb +23 -0
  17. data/app/components/blacklight/facet_field_checkboxes_component.rb +24 -0
  18. data/app/components/blacklight/facet_field_inclusive_constraint_component.html.erb +6 -0
  19. data/app/components/blacklight/facet_field_inclusive_constraint_component.rb +29 -0
  20. data/app/components/blacklight/facet_field_list_component.html.erb +1 -0
  21. data/app/components/blacklight/facet_field_pagination_component.html.erb +4 -4
  22. data/app/components/blacklight/facet_field_pagination_component.rb +0 -4
  23. data/app/components/blacklight/facet_item_component.rb +2 -0
  24. data/app/components/blacklight/hidden_search_state_component.rb +54 -0
  25. data/app/components/blacklight/search_bar_component.html.erb +14 -8
  26. data/app/components/blacklight/search_bar_component.rb +16 -1
  27. data/app/controllers/concerns/blacklight/bookmarks.rb +1 -1
  28. data/app/controllers/concerns/blacklight/catalog.rb +9 -3
  29. data/app/controllers/concerns/blacklight/search_context.rb +1 -1
  30. data/app/helpers/blacklight/component_helper_behavior.rb +1 -1
  31. data/app/helpers/blacklight/configuration_helper_behavior.rb +2 -2
  32. data/app/helpers/blacklight/facets_helper_behavior.rb +1 -1
  33. data/app/helpers/blacklight/hash_as_hidden_fields_helper_behavior.rb +2 -38
  34. data/app/helpers/blacklight/icon_helper_behavior.rb +1 -1
  35. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +2 -2
  36. data/app/helpers/blacklight/render_partials_helper_behavior.rb +2 -2
  37. data/app/javascript/blacklight/button_focus.js +1 -0
  38. data/app/javascript/blacklight/modal.js +10 -4
  39. data/app/models/concerns/blacklight/suggest/response.rb +1 -1
  40. data/app/presenters/blacklight/clause_presenter.rb +37 -0
  41. data/app/presenters/blacklight/document_presenter.rb +5 -1
  42. data/app/presenters/blacklight/facet_field_presenter.rb +4 -0
  43. data/app/presenters/blacklight/facet_grouped_item_presenter.rb +45 -0
  44. data/app/presenters/blacklight/facet_item_presenter.rb +32 -20
  45. data/app/presenters/blacklight/field_presenter.rb +1 -1
  46. data/app/presenters/blacklight/inclusive_facet_item_presenter.rb +16 -0
  47. data/app/presenters/blacklight/search_bar_presenter.rb +4 -0
  48. data/app/values/blacklight/types.rb +1 -1
  49. data/app/views/bookmarks/_tools.html.erb +1 -1
  50. data/app/views/catalog/_advanced_search_form.html.erb +7 -0
  51. data/app/views/catalog/_advanced_search_help.html.erb +24 -0
  52. data/app/views/catalog/_search_form.html.erb +1 -0
  53. data/app/views/catalog/_zero_results.html.erb +1 -1
  54. data/app/views/catalog/advanced_search.html.erb +17 -0
  55. data/blacklight.gemspec +5 -4
  56. data/config/i18n-tasks.yml +1 -0
  57. data/config/locales/blacklight.en.yml +17 -0
  58. data/lib/blacklight/configuration.rb +2 -1
  59. data/lib/blacklight/configuration/field.rb +1 -1
  60. data/lib/blacklight/configuration/fields.rb +1 -1
  61. data/lib/blacklight/configuration/sort_field.rb +1 -1
  62. data/lib/blacklight/routes/searchable.rb +1 -0
  63. data/lib/blacklight/search_builder.rb +2 -0
  64. data/lib/blacklight/search_state.rb +5 -1
  65. data/lib/blacklight/search_state/filter_field.rb +17 -7
  66. data/lib/blacklight/solr/repository.rb +14 -5
  67. data/lib/blacklight/solr/response.rb +1 -1
  68. data/lib/blacklight/solr/search_builder_behavior.rb +87 -23
  69. data/package.json +1 -1
  70. data/spec/components/blacklight/advanced_search_form_component_spec.rb +51 -0
  71. data/spec/components/blacklight/constraint_layout_component_spec.rb +1 -1
  72. data/spec/components/blacklight/document_component_spec.rb +17 -0
  73. data/spec/components/blacklight/facet_field_checkboxes_component_spec.rb +55 -0
  74. data/spec/components/blacklight/facet_field_list_component_spec.rb +39 -4
  75. data/spec/components/blacklight/hidden_search_state_component_spec.rb +24 -0
  76. data/spec/controllers/catalog_controller_spec.rb +9 -0
  77. data/spec/features/advanced_search_spec.rb +67 -0
  78. data/spec/features/bookmarks_spec.rb +1 -9
  79. data/spec/features/facets_spec.rb +2 -17
  80. data/spec/features/search_filters_spec.rb +0 -20
  81. data/spec/helpers/blacklight/hash_as_hidden_fields_behavior_spec.rb +1 -0
  82. data/spec/helpers/blacklight/url_helper_behavior_spec.rb +1 -0
  83. data/spec/lib/blacklight/search_state/filter_field_spec.rb +65 -0
  84. data/spec/models/blacklight/solr/repository_spec.rb +12 -0
  85. data/spec/models/blacklight/solr/response/facets_spec.rb +1 -1
  86. data/spec/models/blacklight/solr/search_builder_spec.rb +28 -0
  87. data/spec/presenters/blacklight/clause_presenter_spec.rb +34 -0
  88. data/spec/presenters/blacklight/document_presenter_spec.rb +13 -0
  89. data/spec/presenters/blacklight/facet_grouped_item_presenter_spec.rb +41 -0
  90. data/spec/spec_helper.rb +8 -3
  91. data/spec/test_app_templates/Gemfile.extra +1 -1
  92. data/spec/views/catalog/_document.html.erb_spec.rb +1 -0
  93. data/spec/views/catalog/_thumbnail.html.erb_spec.rb +2 -0
  94. data/tasks/blacklight.rake +3 -3
  95. metadata +67 -28
  96. data/.travis.yml +0 -40
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Blacklight::FacetFieldCheckboxesComponent, type: :component do
6
+ subject(:render) do
7
+ render_inline(described_class.new(facet_field: facet_field))
8
+ end
9
+
10
+ let(:rendered) do
11
+ Capybara::Node::Simple.new(render)
12
+ end
13
+
14
+ let(:facet_field) do
15
+ instance_double(
16
+ Blacklight::FacetFieldPresenter,
17
+ facet_field: Blacklight::Configuration::NullField.new(key: 'field'),
18
+ paginator: paginator,
19
+ key: 'field',
20
+ label: 'Field',
21
+ active?: false,
22
+ collapsed?: false,
23
+ modal_path: nil,
24
+ html_id: 'facet-field',
25
+ search_state: search_state
26
+ )
27
+ end
28
+
29
+ let(:paginator) do
30
+ instance_double(Blacklight::FacetPaginator, items: [
31
+ double(label: 'a', hits: 10, value: 'a'),
32
+ double(label: 'b', hits: 33, value: 'b'),
33
+ double(label: 'c', hits: 3, value: 'c')
34
+ ])
35
+ end
36
+
37
+ let(:search_state) { Blacklight::SearchState.new(params.with_indifferent_access, Blacklight::Configuration.new) }
38
+ let(:params) { { f: { field: ['a'] } } }
39
+
40
+ it 'renders a collapsible card' do
41
+ expect(rendered).to have_selector '.card'
42
+ expect(rendered).to have_button 'Field'
43
+ expect(rendered).to have_selector 'button[data-target="#facet-field"]'
44
+ expect(rendered).to have_selector '#facet-field.collapse.show'
45
+ end
46
+
47
+ it 'renders the facet items' do
48
+ expect(rendered).to have_selector 'ul.facet-values'
49
+ expect(rendered).to have_selector 'li', count: 3
50
+
51
+ expect(rendered).to have_field 'f_inclusive[field][]', with: 'a'
52
+ expect(rendered).to have_field 'f_inclusive[field][]', with: 'b'
53
+ expect(rendered).to have_field 'f_inclusive[field][]', with: 'c'
54
+ end
55
+ end
@@ -20,7 +20,8 @@ RSpec.describe Blacklight::FacetFieldListComponent, type: :component do
20
20
  active?: false,
21
21
  collapsed?: false,
22
22
  modal_path: nil,
23
- html_id: 'facet-field'
23
+ html_id: 'facet-field',
24
+ values: []
24
25
  )
25
26
  end
26
27
 
@@ -53,7 +54,8 @@ RSpec.describe Blacklight::FacetFieldListComponent, type: :component do
53
54
  active?: true,
54
55
  collapsed?: false,
55
56
  modal_path: nil,
56
- html_id: 'facet-field'
57
+ html_id: 'facet-field',
58
+ values: []
57
59
  )
58
60
  end
59
61
 
@@ -72,7 +74,8 @@ RSpec.describe Blacklight::FacetFieldListComponent, type: :component do
72
74
  active?: false,
73
75
  collapsed?: true,
74
76
  modal_path: nil,
75
- html_id: 'facet-field'
77
+ html_id: 'facet-field',
78
+ values: []
76
79
  )
77
80
  end
78
81
 
@@ -97,7 +100,8 @@ RSpec.describe Blacklight::FacetFieldListComponent, type: :component do
97
100
  active?: false,
98
101
  collapsed?: false,
99
102
  modal_path: '/catalog/facet/modal',
100
- html_id: 'facet-field'
103
+ html_id: 'facet-field',
104
+ values: []
101
105
  )
102
106
  end
103
107
 
@@ -105,4 +109,35 @@ RSpec.describe Blacklight::FacetFieldListComponent, type: :component do
105
109
  expect(rendered).to have_link 'more Field', href: '/catalog/facet/modal'
106
110
  end
107
111
  end
112
+
113
+ context 'with inclusive facets' do
114
+ let(:facet_field) do
115
+ instance_double(
116
+ Blacklight::FacetFieldPresenter,
117
+ paginator: paginator,
118
+ facet_field: Blacklight::Configuration::NullField.new(key: 'field'),
119
+ key: 'field',
120
+ label: 'Field',
121
+ active?: false,
122
+ collapsed?: false,
123
+ modal_path: nil,
124
+ html_id: 'facet-field',
125
+ values: [%w[a b c]],
126
+ search_state: search_state
127
+ )
128
+ end
129
+
130
+ let(:search_state) { Blacklight::SearchState.new(params.with_indifferent_access, Blacklight::Configuration.new) }
131
+ let(:params) { { f_inclusive: { field: %w[a b c] } } }
132
+
133
+ it 'displays the constraint above the list' do
134
+ expect(rendered).to have_content 'Any of:'
135
+ expect(rendered).to have_selector '.inclusive_or .facet-label', text: 'a'
136
+ expect(rendered).to have_link '[remove]', href: 'http://test.host/catalog?f_inclusive%5Bfield%5D%5B%5D=b&f_inclusive%5Bfield%5D%5B%5D=c'
137
+ expect(rendered).to have_selector '.inclusive_or .facet-label', text: 'b'
138
+ expect(rendered).to have_link '[remove]', href: 'http://test.host/catalog?f_inclusive%5Bfield%5D%5B%5D=a&f_inclusive%5Bfield%5D%5B%5D=c'
139
+ expect(rendered).to have_selector '.inclusive_or .facet-label', text: 'c'
140
+ expect(rendered).to have_link '[remove]', href: 'http://test.host/catalog?f_inclusive%5Bfield%5D%5B%5D=a&f_inclusive%5Bfield%5D%5B%5D=b'
141
+ end
142
+ end
108
143
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Blacklight::HiddenSearchStateComponent, type: :component do
4
+ subject(:render) { render_inline(instance) }
5
+
6
+ let(:params) do
7
+ { q: "query",
8
+ search_field: "search_field",
9
+ per_page: 10,
10
+ extra_arbitrary_key: "arbitrary_value",
11
+ f: { field1: %w[a b], field2: ["z"] } }
12
+ end
13
+ let(:instance) { described_class.new(params: params) }
14
+ let(:generated) { Capybara::Node::Simple.new("<div>#{render.to_html}</div>") }
15
+
16
+ it "converts a hash with nested complex data to Rails-style hidden form fields" do
17
+ expect(generated).to have_selector("input[type='hidden'][name='q'][value='query']", visible: :hidden)
18
+ expect(generated).to have_selector("input[type='hidden'][name='per_page'][value='10']", visible: :hidden)
19
+ expect(generated).to have_selector("input[type='hidden'][name='extra_arbitrary_key'][value='arbitrary_value']", visible: :hidden)
20
+ expect(generated).to have_selector("input[type='hidden'][name='f[field2][]'][value='z']", visible: :hidden)
21
+ expect(generated).to have_selector("input[type='hidden'][name='f[field1][]'][value='a']", visible: :hidden)
22
+ expect(generated).to have_selector("input[type='hidden'][name='f[field1][]'][value='b']", visible: :hidden)
23
+ end
24
+ end
@@ -301,6 +301,15 @@ RSpec.describe CatalogController, api: true do
301
301
  end
302
302
  end
303
303
 
304
+ describe 'GET advanced_search' do
305
+ it 'renders an advanced search form' do
306
+ get :advanced_search
307
+ expect(response).to be_successful
308
+
309
+ assert_facets_have_values(assigns(:response).aggregations)
310
+ end
311
+ end
312
+
304
313
  # SHOW ACTION
305
314
  describe "show action" do
306
315
  describe "with format :html" do
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe "Blacklight Advanced Search Form" do
6
+ describe "advanced search form" do
7
+ before do
8
+ visit '/catalog/advanced?hypothetical_existing_param=true&q=ignore+this+existing+query'
9
+ end
10
+
11
+ it "has field and facet blocks" do
12
+ expect(page).to have_selector('.query-criteria')
13
+ expect(page).to have_selector('.limit-criteria')
14
+ end
15
+
16
+ describe "query column" do
17
+ it "gives the user a choice between and/or queries" do
18
+ expect(page).to have_selector('#op')
19
+ within('#op') do
20
+ expect(page).to have_selector('option[value="must"]')
21
+ expect(page).to have_selector('option[value="should"]')
22
+ end
23
+ end
24
+
25
+ it "lists the configured search fields" do
26
+ expect(page).to have_field 'All Fields'
27
+ expect(page).to have_field 'Title'
28
+ expect(page).to have_field 'Author'
29
+ expect(page).to have_field 'Subject'
30
+ end
31
+ end
32
+
33
+ describe "facet column" do
34
+ it "lists facets" do
35
+ expect(page).to have_selector('.blacklight-language_ssim')
36
+
37
+ within('.blacklight-language_ssim') do
38
+ expect(page).to have_content 'Language'
39
+ end
40
+ end
41
+ end
42
+
43
+ it 'scopes searches to fields' do
44
+ fill_in 'Title', with: 'Medicine'
45
+ click_on 'advanced-search-submit'
46
+ expect(page).to have_content 'Remove constraint Title: Medicine'
47
+ expect(page).to have_content 'Strong Medicine speaks'
48
+ end
49
+ end
50
+
51
+ describe "prepopulated advanced search form" do
52
+ before do
53
+ visit '/catalog/advanced?op=must&clause[0][field]=title&clause[0]query=medicine'
54
+ end
55
+
56
+ it "does not create hidden inputs for search fields" do
57
+ expect(page).to have_field 'Title', with: 'medicine'
58
+ end
59
+
60
+ it "does not have multiple parameters for a search field" do
61
+ fill_in 'Title', with: 'bread'
62
+ click_on 'advanced-search-submit'
63
+ expect(page.current_url).to match(/bread/)
64
+ expect(page.current_url).not_to match(/medicine/)
65
+ end
66
+ end
67
+ end
@@ -57,7 +57,7 @@ RSpec.describe "Bookmarks" do
57
57
  expect(page).to have_content 'Strong Medicine speaks'
58
58
  end
59
59
 
60
- it "cites items in current bookmarks page" do
60
+ it "cites all items in current bookmarks" do
61
61
  visit solr_document_path('2009373513') # Ci an zhou bian
62
62
  click_button 'Bookmark'
63
63
 
@@ -70,14 +70,6 @@ RSpec.describe "Bookmarks" do
70
70
 
71
71
  click_link 'Cite'
72
72
  expect(page).to have_content 'Strong Medicine speaks'
73
- expect(page).not_to have_content 'Ci an zhou bian'
74
-
75
- visit "/bookmarks?per_page=1"
76
- click_link "2"
77
- expect(page).to have_content 'Ci an zhou bian'
78
-
79
- click_link 'Cite'
80
- expect(page).not_to have_content 'Strong Medicine speaks'
81
73
  expect(page).to have_content 'Ci an zhou bian'
82
74
  end
83
75
  end
@@ -56,10 +56,6 @@ RSpec.describe "Facets" do
56
56
 
57
57
  expect(page).to have_css('#facet-format', visible: false)
58
58
 
59
- within('#facets .facets-header') do
60
- page.find('button.navbar-toggler').click
61
- end
62
-
63
59
  page.find('h3.facet-field-heading button', text: 'Format').click
64
60
 
65
61
  sleep(1) # let facet animation finish and wait for it to potentially re-collapse
@@ -70,14 +66,10 @@ RSpec.describe "Facets" do
70
66
  it 'is able to expand pivot facets when javascript is enabled', js: true do
71
67
  visit root_path
72
68
 
73
- within('#facets .facets-header') do
74
- page.find('button.navbar-toggler').click
75
- end
76
-
77
69
  page.find('h3.facet-field-heading button', text: 'Pivot Field').click
78
70
 
79
71
  within '#facet-example_pivot_field' do
80
- expect(page).to have_css('.facet-leaf-node', text: 'Book 30')
72
+ expect(page).to have_css('.facet-leaf-node', text: "Book\t30")
81
73
  expect(page).not_to have_css('.facet-select', text: 'Tibetan')
82
74
  page.find('.facet-toggle-handle').click
83
75
  click_link 'Tibetan'
@@ -88,15 +80,8 @@ RSpec.describe "Facets" do
88
80
  end
89
81
 
90
82
  describe 'heading button focus with Firefox' do
91
- before do
92
- Capybara.current_driver = :selenium_headless
93
- end
94
-
95
- after do
96
- Capybara.current_driver = :rack_test
97
- end
98
-
99
83
  it 'changes to the button on button click in Firefox' do
84
+ pending 'Capybara::NotSupportedByDriverError: Capybara::Driver::Base#evaluate_script'
100
85
  visit root_path
101
86
  page.find('h3.facet-field-heading button', text: 'Format').click
102
87
  focused_element_data_target = page.evaluate_script("document.activeElement")['data-target']
@@ -168,26 +168,16 @@ RSpec.describe "Facets" do
168
168
  end
169
169
 
170
170
  it "is collapsed when not selected", js: true do
171
- skip("Test passes locally but not on Travis.") if ENV['TRAVIS']
172
171
  visit root_path
173
172
 
174
- within('#facets .facets-header') do
175
- page.find('button.navbar-toggler').click
176
- end
177
-
178
173
  within(".blacklight-subject_ssim") do
179
174
  expect(page).not_to have_selector(".card-body", visible: true)
180
175
  end
181
176
  end
182
177
 
183
178
  it "expands when the heading button is clicked", js: true do
184
- skip("Test passes locally but not on Travis.") if ENV['TRAVIS']
185
179
  visit root_path
186
180
 
187
- within('#facets .facets-header') do
188
- page.find('button.navbar-toggler').click
189
- end
190
-
191
181
  within(".blacklight-subject_ssim") do
192
182
  expect(page).not_to have_selector(".card-body", visible: true)
193
183
  find(".card-header button").click
@@ -196,13 +186,8 @@ RSpec.describe "Facets" do
196
186
  end
197
187
 
198
188
  it "expands when the button is clicked", js: true do
199
- skip("Test passes locally but not on Travis.") if ENV['TRAVIS']
200
189
  visit root_path
201
190
 
202
- within('#facets .facets-header') do
203
- page.find('button.navbar-toggler').click
204
- end
205
-
206
191
  within(".blacklight-subject_ssim") do
207
192
  expect(page).not_to have_selector(".card-body", visible: true)
208
193
  find(".card-header").click
@@ -211,13 +196,8 @@ RSpec.describe "Facets" do
211
196
  end
212
197
 
213
198
  it "keeps selected facets expanded on page load", js: true do
214
- skip("Test passes locally but not on Travis.") if ENV['TRAVIS']
215
199
  visit root_path
216
200
 
217
- within('#facets .facets-header') do
218
- page.find('button.navbar-toggler').click
219
- end
220
-
221
201
  within(".blacklight-subject_ssim") do
222
202
  page.find('h3.facet-field-heading', text: 'Topic').click
223
203
  expect(page).to have_selector(".panel-collapse", visible: true)
@@ -14,6 +14,7 @@ RSpec.describe Blacklight::HashAsHiddenFieldsHelperBehavior do
14
14
  let(:generated) { helper.render_hash_as_hidden_fields(params) }
15
15
 
16
16
  it "converts a hash with nested complex data to Rails-style hidden form fields" do
17
+ allow(Deprecation).to receive(:warn)
17
18
  expect(generated).to have_selector("input[type='hidden'][name='q'][value='query']", visible: false)
18
19
  expect(generated).to have_selector("input[type='hidden'][name='per_page'][value='10']", visible: false)
19
20
  expect(generated).to have_selector("input[type='hidden'][name='page'][value='5']", visible: false)
@@ -13,6 +13,7 @@ RSpec.describe Blacklight::UrlHelperBehavior do
13
13
  let(:parameter_class) { ActionController::Parameters }
14
14
 
15
15
  before do
16
+ allow(controller).to receive(:controller_name).and_return('test')
16
17
  allow(helper).to receive(:search_action_path) do |*args|
17
18
  search_catalog_url *args
18
19
  end
@@ -72,6 +72,33 @@ RSpec.describe Blacklight::SearchState::FilterField do
72
72
  expect(new_state.filter('some_field').values).to eq %w[1 2 4]
73
73
  end
74
74
  end
75
+
76
+ context 'with an array' do
77
+ let(:params) do
78
+ { f: { another_field: ['3'] }, f_inclusive: { some_field: %w[a b c] } }
79
+ end
80
+
81
+ it 'creates a new group with the new values' do
82
+ filter = search_state.filter('new_field')
83
+ new_state = filter.add(%w[x y z])
84
+
85
+ expect(new_state.filter('new_field').values).to eq [%w[x y z]]
86
+ end
87
+
88
+ it 'updates any existing groups with the new values' do
89
+ filter = search_state.filter('some_field')
90
+ new_state = filter.add(%w[x y z])
91
+
92
+ expect(new_state.filter('some_field').values).to eq [%w[x y z]]
93
+ end
94
+
95
+ it 'leaves existing filters alone' do
96
+ filter = search_state.filter('another_field')
97
+ new_state = filter.add(%w[x y z])
98
+
99
+ expect(new_state.filter('another_field').values).to eq ['3', %w[x y z]]
100
+ end
101
+ end
75
102
  end
76
103
 
77
104
  describe '#remove' do
@@ -104,12 +131,50 @@ RSpec.describe Blacklight::SearchState::FilterField do
104
131
 
105
132
  expect(new_state.filter('some_field').values).to eq ['2']
106
133
  end
134
+
135
+ context 'with an array' do
136
+ let(:params) do
137
+ { f: { another_field: ['3'] }, f_inclusive: { some_field: %w[a b c], another_field: %w[x y z] } }
138
+ end
139
+
140
+ it 'removes groups of values' do
141
+ filter = search_state.filter('some_field')
142
+ new_state = filter.remove(%w[a b c])
143
+
144
+ expect(new_state.params[:f_inclusive]).not_to include :some_field
145
+ expect(new_state.filter('some_field').values).to eq []
146
+ end
147
+
148
+ it 'can remove single values' do
149
+ filter = search_state.filter('some_field')
150
+ new_state = filter.remove(%w[a])
151
+
152
+ expect(new_state.filter('some_field').values).to eq [%w[b c]]
153
+ end
154
+
155
+ it 'leaves existing filters alone' do
156
+ filter = search_state.filter('another_field')
157
+ new_state = filter.remove(%w[x y z])
158
+
159
+ expect(new_state.filter('another_field').values).to eq ['3']
160
+ end
161
+ end
107
162
  end
108
163
 
109
164
  describe '#values' do
110
165
  it 'returns the currently selected values of the filter' do
111
166
  expect(search_state.filter('some_field').values).to eq %w[1 2]
112
167
  end
168
+
169
+ context 'with an array' do
170
+ let(:params) do
171
+ { f: { some_field: ['3'] }, f_inclusive: { some_field: %w[a b c] } }
172
+ end
173
+
174
+ it 'combines the exclusive and inclusive values' do
175
+ expect(search_state.filter('some_field').values).to eq ['3', %w[a b c]]
176
+ end
177
+ end
113
178
  end
114
179
 
115
180
  describe '#include?' do