blacklight 9.0.0.beta7 → 9.0.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.docker/app/Dockerfile +2 -1
  3. data/.github/matrix.json +21 -20
  4. data/README.md +2 -2
  5. data/VERSION +1 -1
  6. data/app/assets/javascripts/blacklight/blacklight.esm.js +13 -7
  7. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  8. data/app/assets/javascripts/blacklight/blacklight.js +13 -7
  9. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  10. data/app/components/blacklight/advanced_search_form_component.rb +2 -1
  11. data/app/components/blacklight/document_component.rb +10 -13
  12. data/app/components/blacklight/facets/filters_component.rb +2 -2
  13. data/app/components/blacklight/facets/suggest_component.html.erb +17 -12
  14. data/app/components/blacklight/facets/suggest_component.rb +2 -3
  15. data/app/components/blacklight/metadata_field_component.html.erb +2 -2
  16. data/app/components/blacklight/metadata_field_component.rb +2 -1
  17. data/app/components/blacklight/metadata_field_layout_component.rb +9 -4
  18. data/app/components/blacklight/search_bar_component.html.erb +1 -1
  19. data/app/controllers/concerns/blacklight/catalog.rb +3 -4
  20. data/app/javascript/blacklight-frontend/checkbox_submit.js +2 -2
  21. data/app/javascript/blacklight-frontend/facet_suggest.js +4 -1
  22. data/app/javascript/blacklight-frontend/modal.js +7 -4
  23. data/app/presenters/blacklight/document_presenter.rb +6 -5
  24. data/app/presenters/blacklight/facet_field_presenter.rb +10 -3
  25. data/app/presenters/blacklight/field_presenter.rb +4 -2
  26. data/app/presenters/blacklight/rendering/abstract_step.rb +7 -1
  27. data/app/presenters/blacklight/rendering/join.rb +9 -5
  28. data/app/presenters/blacklight/rendering/terminator.rb +1 -1
  29. data/app/services/blacklight/search_service.rb +4 -2
  30. data/app/views/catalog/_show_main_content.html.erb +9 -5
  31. data/app/views/catalog/index.html.erb +0 -1
  32. data/app/views/catalog/show.html.erb +2 -2
  33. data/config/locales/blacklight.en.yml +1 -1
  34. data/lib/blacklight/component.rb +2 -0
  35. data/lib/blacklight/configuration/facet_field.rb +2 -0
  36. data/lib/blacklight/configuration/view_config.rb +30 -16
  37. data/lib/blacklight/configuration.rb +56 -9
  38. data/lib/blacklight/routes/searchable.rb +1 -1
  39. data/lib/blacklight/search_builder.rb +160 -1
  40. data/lib/blacklight/search_state/pivot_filter_field.rb +1 -1
  41. data/lib/blacklight/solr/field_reflection_search_builder.rb +11 -0
  42. data/lib/blacklight/solr/repository.rb +5 -5
  43. data/lib/blacklight/solr/search_builder_behavior.rb +73 -7
  44. data/lib/blacklight/solr/single_doc_search_builder.rb +25 -0
  45. data/lib/generators/blacklight/templates/catalog_controller.rb +27 -5
  46. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -67
  47. data/package.json +1 -1
  48. data/spec/components/blacklight/document_component_spec.rb +0 -7
  49. data/spec/components/blacklight/facets/filters_component_spec.rb +3 -3
  50. data/spec/components/blacklight/facets/suggest_component_spec.rb +14 -1
  51. data/spec/components/blacklight/search_bar_component_spec.rb +24 -1
  52. data/spec/controllers/blacklight/catalog_spec.rb +1 -1
  53. data/spec/features/advanced_search_spec.rb +39 -20
  54. data/spec/features/facets_spec.rb +9 -0
  55. data/spec/models/blacklight/configuration_spec.rb +126 -0
  56. data/spec/models/blacklight/search_builder_spec.rb +11 -1
  57. data/spec/models/blacklight/solr/repository_spec.rb +6 -0
  58. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +214 -8
  59. data/spec/presenters/blacklight/document_presenter_spec.rb +3 -3
  60. data/spec/presenters/blacklight/field_presenter_spec.rb +103 -22
  61. data/spec/presenters/blacklight/rendering/pipeline_spec.rb +130 -14
  62. metadata +8 -16
  63. data/app/controllers/concerns/blacklight/facetable.rb +0 -34
  64. data/app/models/facet_search_builder.rb +0 -5
  65. data/app/services/blacklight/facet_search_service.rb +0 -44
  66. data/app/views/shared/_sitelinks_search_box.html.erb +0 -12
  67. data/lib/blacklight/abstract_search_builder.rb +0 -154
  68. data/lib/blacklight/facet_search_builder.rb +0 -18
  69. data/lib/blacklight/solr/facet_search_builder_behavior.rb +0 -62
  70. data/spec/features/sitelinks_search_box_spec.rb +0 -13
  71. data/spec/models/blacklight/facet_search_builder_spec.rb +0 -19
  72. data/spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb +0 -929
@@ -43,7 +43,7 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, :api do
43
43
  end
44
44
 
45
45
  context "with a complex parameter environment" do
46
- subject { search_builder.with(user_params).send(:processed_parameters) }
46
+ subject { search_builder.with(user_params).processed_parameters }
47
47
 
48
48
  let(:user_params) do
49
49
  { :search_field => "test_field", :q => "test query", "facet.field" => "extra_facet" }
@@ -90,7 +90,7 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, :api do
90
90
  # SPECS for actual search parameter generation
91
91
  describe "#processed_parameters" do
92
92
  subject do
93
- search_builder.with(user_params).send(:processed_parameters)
93
+ search_builder.with(user_params).processed_parameters
94
94
  end
95
95
 
96
96
  context "when search_params_logic is customized" do
@@ -523,6 +523,58 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, :api do
523
523
  end
524
524
  end
525
525
 
526
+ describe "#add_facets_for_advanced_search_form" do
527
+ let(:solr_parameters) { Blacklight::Solr::Request.new }
528
+ let(:mock_controller) { instance_double(CatalogController, action_name: 'advanced_search') }
529
+ let(:mock_search_state) { instance_double(Blacklight::SearchState, controller: mock_controller) }
530
+
531
+ before do
532
+ allow(search_builder).to receive(:search_state).and_return(mock_search_state)
533
+ end
534
+
535
+ context "when action is advanced_search and form_solr_parameters are configured" do
536
+ before do
537
+ blacklight_config.advanced_search.enabled = true
538
+ blacklight_config.advanced_search.form_solr_parameters = {
539
+ 'facet.sort' => 'count',
540
+ 'facet.field' => %w[format subject_ssim],
541
+ 'f.format.facet.limit' => -1,
542
+ 'f.subject_ssim.facet.limit' => -1
543
+ }
544
+ end
545
+
546
+ it "merges advanced search form parameters into solr parameters" do
547
+ solr_parameters['existing.param'] = 'keep_me'
548
+ subject.add_facets_for_advanced_search_form(solr_parameters)
549
+
550
+ expect(solr_parameters['facet.sort']).to eq 'count'
551
+ expect(solr_parameters['facet.field']).to eq %w[format subject_ssim]
552
+ expect(solr_parameters['f.format.facet.limit']).to eq(-1)
553
+ expect(solr_parameters['f.subject_ssim.facet.limit']).to eq(-1)
554
+ expect(solr_parameters['existing.param']).to eq 'keep_me'
555
+ end
556
+ end
557
+
558
+ context "when action is not advanced_search" do
559
+ before do
560
+ allow(mock_controller).to receive(:action_name).and_return('index')
561
+ blacklight_config.advanced_search.enabled = true
562
+ blacklight_config.advanced_search.form_solr_parameters = {
563
+ 'facet.sort' => 'count',
564
+ 'facet.field' => ['format']
565
+ }
566
+ end
567
+
568
+ it "does not merge advanced search form parameters" do
569
+ solr_parameters['f.format.facet.limit'] = 21
570
+
571
+ subject.add_facets_for_advanced_search_form(solr_parameters)
572
+
573
+ expect(solr_parameters['f.format.facet.limit']).to eq 21
574
+ end
575
+ end
576
+ end
577
+
526
578
  describe "#add_facet_fq_to_solr" do
527
579
  it "converts a String fq into an Array" do
528
580
  solr_parameters = { fq: 'a string' }
@@ -666,6 +718,166 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, :api do
666
718
  end
667
719
  end
668
720
 
721
+ describe "#add_facet_paging_to_solr" do
722
+ let(:facet_field) { 'format' }
723
+ let(:sort_key) { Blacklight::Solr::FacetPaginator.request_keys[:sort] }
724
+ let(:page_key) { Blacklight::Solr::FacetPaginator.request_keys[:page] }
725
+ let(:prefix_key) { Blacklight::Solr::FacetPaginator.request_keys[:prefix] }
726
+
727
+ let(:blacklight_config) do
728
+ Blacklight::Configuration.new do |config|
729
+ config.add_facet_fields_to_solr_request!
730
+ config.add_facet_field 'format'
731
+ config.add_facet_field 'format_ordered', sort: :count
732
+ config.add_facet_field 'format_limited', limit: 5
733
+ config.add_facet_field 'format_more_limited', limit: 5, more_limit: 50
734
+ end
735
+ end
736
+
737
+ let(:solr_parameters) do
738
+ solr_parameters = Blacklight::Solr::Request.new
739
+ subject.facet(facet_field).add_facet_paging_to_solr(solr_parameters)
740
+ solr_parameters
741
+ end
742
+
743
+ it 'sets rows to 0' do
744
+ expect(solr_parameters[:rows]).to eq 0
745
+ end
746
+
747
+ it 'sets facets requested to facet_field argument' do
748
+ expect(solr_parameters[:'facet.field']).to eq facet_field
749
+ end
750
+
751
+ it 'defaults offset to 0' do
752
+ expect(solr_parameters[:"f.#{facet_field}.facet.offset"]).to eq 0
753
+ end
754
+
755
+ context 'when offset is manually set' do
756
+ let(:user_params) { { page_key => 2 } }
757
+
758
+ it 'uses offset manually set, and converts it to an integer' do
759
+ expect(solr_parameters[:"f.#{facet_field}.facet.offset"]).to eq 20
760
+ end
761
+ end
762
+
763
+ context 'for a field with a configured more_limit' do
764
+ let(:facet_field) { 'format_more_limited' }
765
+
766
+ it 'uses the more_limit configuration' do
767
+ expect(solr_parameters[:"f.#{facet_field}.facet.limit"]).to eq 51
768
+ end
769
+ end
770
+
771
+ context 'for a field with a param key different from the field name' do
772
+ let(:user_params) { { page_key => 2, 'facet.sort': 'index', 'facet.prefix': 'x' } }
773
+ let(:facet_field) { 'param_key' }
774
+
775
+ let(:blacklight_config) do
776
+ Blacklight::Configuration.new.tap do |config|
777
+ config.add_facet_field key: 'param_key', field: 'solr_field', more_limit: 50, ex: 'other'
778
+
779
+ config.add_facet_fields_to_solr_request!
780
+ end
781
+ end
782
+
783
+ it "uses the configured solr field name in queries" do
784
+ expect(solr_parameters).to include 'f.solr_field.facet.limit': 51,
785
+ 'f.solr_field.facet.offset': 50,
786
+ 'f.solr_field.facet.sort': 'index',
787
+ 'f.solr_field.facet.prefix': 'x',
788
+ 'facet.field': '{!ex=other}solr_field'
789
+ end
790
+ end
791
+
792
+ it 'defaults limit to 20' do
793
+ expect(solr_parameters[:"f.#{facet_field}.facet.limit"]).to eq 21
794
+ end
795
+
796
+ it 'uses the default sort' do
797
+ expect(solr_parameters[:"f.#{facet_field}.facet.sort"]).to be_blank
798
+ end
799
+
800
+ context 'when sort is provided' do
801
+ let(:user_params) { { sort_key => 'index' } }
802
+
803
+ it 'uses sort provided in the parameters' do
804
+ expect(solr_parameters[:"f.#{facet_field}.facet.sort"]).to eq 'index'
805
+ end
806
+ end
807
+
808
+ context 'when a prefix is provided' do
809
+ let(:user_params) { { prefix_key => 'A' } }
810
+
811
+ it 'includes the prefix in the query' do
812
+ expect(solr_parameters[:"f.#{facet_field}.facet.prefix"]).to eq 'A'
813
+ end
814
+ end
815
+ end
816
+
817
+ describe "#add_facet_suggestion_parameters" do
818
+ it "does not add anything when the builder has no facet_suggestion_query and no facet" do
819
+ expect(subject.facet).to be_nil
820
+ expect(subject.facet_suggestion_query).to be_nil
821
+ solr_params = Blacklight::Solr::Request.new
822
+
823
+ expect do
824
+ subject.add_facet_suggestion_parameters(solr_params)
825
+ end.not_to(change { solr_params })
826
+ end
827
+
828
+ it "does not add anything when the builder has a facet_suggestion_query but no facet" do
829
+ subject.facet_suggestion_query = 'artic'
830
+ expect(subject.facet_suggestion_query).to eq 'artic'
831
+ expect(subject.facet).to be_nil
832
+ solr_params = Blacklight::Solr::Request.new
833
+
834
+ expect do
835
+ subject.add_facet_suggestion_parameters(solr_params)
836
+ end.not_to(change { solr_params })
837
+ end
838
+
839
+ it "does not add anything when the builder has a facet but no facet_suggestion_query" do
840
+ subject.facet = 'subject_facet'
841
+ expect(subject.facet_suggestion_query).to be_nil
842
+ expect(subject.facet).to eq 'subject_facet'
843
+ solr_params = Blacklight::Solr::Request.new
844
+
845
+ expect do
846
+ subject.add_facet_suggestion_parameters(solr_params)
847
+ end.not_to(change { solr_params })
848
+ end
849
+
850
+ it "adds the facet_suggestion_query to facet.contains" do
851
+ subject.facet = 'subject_facet'
852
+ subject.facet_suggestion_query = 'artic'
853
+ solr_params = Blacklight::Solr::Request.new
854
+
855
+ subject.add_facet_suggestion_parameters(solr_params)
856
+
857
+ expect(solr_params[:'facet.contains']).to eq 'artic'
858
+ end
859
+
860
+ it "adds the first part of facet_suggestion_query to facet.contains if it is extremely long" do
861
+ subject.facet = 'subject_facet'
862
+ subject.facet_suggestion_query = 'Call me Ishmael. Some years ago—never mind how long precisely'
863
+ solr_params = Blacklight::Solr::Request.new
864
+
865
+ subject.add_facet_suggestion_parameters(solr_params)
866
+
867
+ expect(solr_params[:'facet.contains']).to eq 'Call me Ishmael. Some years ago—never mind how long'
868
+ end
869
+
870
+ it "adds facet.contains.ignoreCase" do
871
+ subject.facet = 'subject_facet'
872
+ subject.facet_suggestion_query = 'artic'
873
+ solr_params = Blacklight::Solr::Request.new
874
+
875
+ subject.add_facet_suggestion_parameters(solr_params)
876
+
877
+ expect(solr_params[:'facet.contains.ignoreCase']).to be true
878
+ end
879
+ end
880
+
669
881
  describe "#with_tag_ex" do
670
882
  it "adds an !ex local parameter if the facet configuration requests it" do
671
883
  expect(subject.with_ex_local_param("xyz", "some-value")).to eq "{!ex=xyz}some-value"
@@ -677,12 +889,6 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, :api do
677
889
  end
678
890
 
679
891
  context 'with advanced search clause parameters' do
680
- before do
681
- blacklight_config.search_fields.each_value do |v|
682
- v.clause_params = { edismax: v.solr_parameters.dup }
683
- end
684
- end
685
-
686
892
  let(:user_params) { { op: 'must', clause: { '0': { field: 'title', query: 'the book' }, '1': { field: 'author', query: 'the person' } } } }
687
893
 
688
894
  it "has proper solr parameters" do
@@ -29,13 +29,13 @@ RSpec.describe Blacklight::DocumentPresenter do
29
29
  end
30
30
 
31
31
  describe '#field_value' do
32
- let(:field_presenter) { instance_double(Blacklight::FieldPresenter, render: 'xyz') }
32
+ let(:field_presenter) { instance_double(Blacklight::FieldPresenter, render: ['xyz']) }
33
33
  let(:field_config) { Blacklight::Configuration::DisplayField.new }
34
34
  let(:options) { { a: 1 } }
35
35
 
36
36
  it 'calls the field presenter' do
37
37
  allow(Blacklight::FieldPresenter).to receive(:new).with(request_context, doc, field_config, options).and_return(field_presenter)
38
- expect(presenter.field_value(field_config, options)).to eq 'xyz'
38
+ expect(presenter.field_value(field_config, options)).to eq ['xyz']
39
39
  end
40
40
 
41
41
  it 'can be configured to use an alternate presenter' do
@@ -44,7 +44,7 @@ RSpec.describe Blacklight::DocumentPresenter do
44
44
  field_config.presenter = SomePresenter
45
45
  allow(SomePresenter).to receive(:new).and_return(instance)
46
46
 
47
- expect(presenter.field_value(field_config, options)).to eq 'abc'
47
+ expect(presenter.field_value(field_config, options)).to eq ['abc']
48
48
  end
49
49
  end
50
50
 
@@ -6,6 +6,8 @@ RSpec.describe Blacklight::FieldPresenter, :api do
6
6
  let(:request_context) { double('View context', params: { x: '1' }, search_state: search_state, should_render_field?: true, blacklight_config: config) }
7
7
  let(:document) do
8
8
  SolrDocument.new(id: 1,
9
+ 'join_true' => %w[a b c],
10
+ 'separator_options' => %w[d e f],
9
11
  'link_to_facet_true' => 'x',
10
12
  'link_to_facet_named' => 'x',
11
13
  'qwer' => 'document qwer value',
@@ -30,6 +32,8 @@ RSpec.describe Blacklight::FieldPresenter, :api do
30
32
  Blacklight::Configuration.new.configure do |config|
31
33
  config.add_index_field 'qwer'
32
34
  config.add_index_field 'asdf', helper_method: :render_asdf_index_field
35
+ config.add_index_field 'join_true', join: true
36
+ config.add_index_field 'separator_options', separator_options: { words_connector: '<br/>', last_word_connector: '<br/>' }
33
37
  config.add_index_field 'link_to_facet_true', link_to_facet: true
34
38
  config.add_index_field 'link_to_facet_named', link_to_facet: :some_field
35
39
  config.add_index_field 'highlight', highlight: true
@@ -40,6 +44,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
40
44
  config.add_index_field 'alias', field: 'qwer'
41
45
  config.add_index_field 'with_default', default: 'value'
42
46
  config.add_index_field 'with_steps', steps: [custom_step]
47
+ config.add_index_field :some_field
43
48
  config.add_facet_field :link_to_facet_true
44
49
  config.add_facet_field :some_field
45
50
  end
@@ -51,25 +56,33 @@ RSpec.describe Blacklight::FieldPresenter, :api do
51
56
  context 'when an explicit html value is provided' do
52
57
  let(:options) { { value: '<b>val1</b>' } }
53
58
 
54
- it { is_expected.not_to be_html_safe }
59
+ it { is_expected.to eq(['<b>val1</b>']) }
60
+
61
+ it 'does not mark value as html_safe' do
62
+ expect(result.first).not_to be_html_safe
63
+ end
55
64
  end
56
65
 
57
66
  context 'when an explicit array value with unsafe characters is provided' do
58
67
  let(:options) { { value: ['<a', 'b'] } }
59
68
 
60
- it { is_expected.to eq('&lt;a and b').and be_html_safe }
69
+ it { is_expected.to eq(%w[<a b]) }
70
+
71
+ it 'does not mark values as html_safe' do
72
+ expect(subject.all?(&:html_safe?)).not_to be true
73
+ end
61
74
  end
62
75
 
63
76
  context 'when an explicit array value is provided' do
64
77
  let(:options) { { value: %w[a b c] } }
65
78
 
66
- it { is_expected.to eq 'a, b, and c' }
79
+ it { is_expected.to eq %w[a b c] }
67
80
  end
68
81
 
69
82
  context 'when an explicit value is provided' do
70
83
  let(:options) { { value: 'asdf' } }
71
84
 
72
- it { is_expected.to eq 'asdf' }
85
+ it { is_expected.to eq ['asdf'] }
73
86
  end
74
87
 
75
88
  context 'when field has a helper method' do
@@ -77,7 +90,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
77
90
  allow(request_context).to receive(:render_asdf_index_field).and_return('custom asdf value')
78
91
  end
79
92
 
80
- it { is_expected.to eq 'custom asdf value' }
93
+ it { is_expected.to eq ['custom asdf value'] }
81
94
  end
82
95
 
83
96
  context 'when field has link_to_facet with true' do
@@ -88,7 +101,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
88
101
 
89
102
  let(:field_name) { 'link_to_facet_true' }
90
103
 
91
- it { is_expected.to eq 'bar' }
104
+ it { is_expected.to eq ['bar'] }
92
105
  end
93
106
 
94
107
  context 'when field has link_to_facet with a field name' do
@@ -99,7 +112,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
99
112
 
100
113
  let(:field_name) { 'link_to_facet_named' }
101
114
 
102
- it { is_expected.to eq 'bar' }
115
+ it { is_expected.to eq ['bar'] }
103
116
  end
104
117
 
105
118
  context 'when no highlight field is available' do
@@ -120,14 +133,14 @@ RSpec.describe Blacklight::FieldPresenter, :api do
120
133
 
121
134
  let(:field_name) { 'highlight' }
122
135
 
123
- it { is_expected.to eq '<em>highlight</em>' }
136
+ it { is_expected.to eq ['<em>highlight</em>'] }
124
137
  end
125
138
 
126
139
  context 'when no options are provided' do
127
140
  let(:field_name) { 'qwer' }
128
141
 
129
142
  it "checks the document field value" do
130
- expect(subject).to eq 'document qwer value'
143
+ expect(subject).to eq ['document qwer value']
131
144
  end
132
145
  end
133
146
 
@@ -138,7 +151,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
138
151
 
139
152
  let(:field_name) { 'solr_doc_accessor' }
140
153
 
141
- it { is_expected.to eq '123' }
154
+ it { is_expected.to eq ['123'] }
142
155
  end
143
156
 
144
157
  context 'when accessor is set to a value' do
@@ -147,7 +160,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
147
160
  it 'calls the accessor with the field_name as the argument' do
148
161
  expect(document).to receive(:solr_doc_accessor).with('explicit_accessor').and_return("123")
149
162
 
150
- expect(subject).to eq '123'
163
+ expect(subject).to eq ['123']
151
164
  end
152
165
  end
153
166
 
@@ -157,7 +170,7 @@ RSpec.describe Blacklight::FieldPresenter, :api do
157
170
  it 'calls the accessors on the return of the preceeding' do
158
171
  allow(document).to receive_message_chain(:solr_doc_accessor, some_method: "123")
159
172
 
160
- expect(subject).to eq '123'
173
+ expect(subject).to eq ['123']
161
174
  end
162
175
  end
163
176
 
@@ -165,26 +178,26 @@ RSpec.describe Blacklight::FieldPresenter, :api do
165
178
  let(:field_name) { 'explicit_values_with_context' }
166
179
 
167
180
  it 'calls the accessors on the return of the preceeding' do
168
- expect(subject).to eq '1'
181
+ expect(subject).to eq ['1']
169
182
  end
170
183
  end
171
184
 
172
185
  context 'when the field is an alias' do
173
186
  let(:field_name) { 'alias' }
174
187
 
175
- it { is_expected.to eq 'document qwer value' }
188
+ it { is_expected.to eq ['document qwer value'] }
176
189
  end
177
190
 
178
191
  context 'when the field has a default' do
179
192
  let(:field_name) { 'with_default' }
180
193
 
181
- it { is_expected.to eq 'value' }
194
+ it { is_expected.to eq ['value'] }
182
195
  end
183
196
 
184
197
  context 'with steps' do
185
198
  let(:field_name) { 'with_steps' }
186
199
 
187
- it { is_expected.to eq 'Static step' }
200
+ it { is_expected.to eq ['Static step'] }
188
201
  end
189
202
 
190
203
  context 'for a field with the helper_method option' do
@@ -200,12 +213,80 @@ RSpec.describe Blacklight::FieldPresenter, :api do
200
213
  args.first
201
214
  end
202
215
 
203
- expect(result).to include :document, :field, :value, :config, :a
204
- expect(result[:document]).to eq document
205
- expect(result[:field]).to eq 'field_with_helper'
206
- expect(result[:value]).to eq ['value']
207
- expect(result[:config]).to eq field_config
208
- expect(result[:a]).to eq 1
216
+ expect(result).to contain_exactly({ document: document, field: field_name,
217
+ value: ['value'], config: field_config, a: 1 })
218
+ end
219
+ end
220
+
221
+ context 'when joining a field' do
222
+ context 'with join config' do
223
+ let(:field_name) { :join_true }
224
+
225
+ it { is_expected.to eq ['a, b, and c'] }
226
+
227
+ it 'marks the value as html_safe' do
228
+ expect(result.first).to be_html_safe
229
+ end
230
+ end
231
+
232
+ context 'with separator_options' do
233
+ let(:field_name) { :separator_options }
234
+
235
+ it { is_expected.to eq ['d<br/>e<br/>f'] }
236
+
237
+ it 'marks the value as html_safe' do
238
+ expect(result.first).to be_html_safe
239
+ end
240
+ end
241
+
242
+ context 'with join option' do
243
+ let(:options) { { join: true } }
244
+ let(:field_name) { 'some_field' }
245
+
246
+ it { is_expected.to eq ['1 and 2'] }
247
+
248
+ it 'marks the value as html_safe' do
249
+ expect(result.first).to be_html_safe
250
+ end
251
+ end
252
+ end
253
+
254
+ context 'with a single value' do
255
+ let(:options) { { join: true, value: 1 } }
256
+
257
+ it 'is not joined' do
258
+ expect(result).to eq [1]
259
+ end
260
+ end
261
+
262
+ context 'with a single html value' do
263
+ let(:options) { { join: true, value: '<b>value</b>' } }
264
+
265
+ it { is_expected.to eq ['<b>value</b>'] }
266
+
267
+ it 'does not mark the value as html_safe' do
268
+ expect(result.first).not_to be_html_safe
269
+ end
270
+ end
271
+
272
+ context 'when an array containing unsafe characters provided' do
273
+ let(:options) { { join: true, value: ['<a', 'b'] } }
274
+
275
+ it 'html escapes the unsafe characters' do
276
+ expect(result).to eq ["&lt;a and b"]
277
+ end
278
+
279
+ it 'marks the value as html_safe' do
280
+ expect(result.first).to be_html_safe
281
+ end
282
+ end
283
+
284
+ context 'when outside the html context' do
285
+ let(:field_name) { :join_true }
286
+ let(:options) { { format: 'json' } }
287
+
288
+ it 'does not join the values' do
289
+ expect(result).to eq %w[a b c]
209
290
  end
210
291
  end
211
292
  end