geoblacklight 6.0.0.pre.alpha.7 → 6.0.0.pre.beta.2

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 (231) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +14 -3
  3. data/README.md +2 -2
  4. data/Rakefile +1 -17
  5. data/app/assets/images/geoblacklight/logo-dark.svg +31 -0
  6. data/app/assets/images/geoblacklight/logo.svg +10 -10
  7. data/app/assets/stylesheets/geoblacklight/global.css +44 -7
  8. data/app/assets/stylesheets/geoblacklight/index_maps.css +0 -7
  9. data/app/assets/stylesheets/geoblacklight/record.css +33 -9
  10. data/app/assets/stylesheets/geoblacklight/search.css +66 -17
  11. data/app/assets/stylesheets/geoblacklight/viewers.css +18 -111
  12. data/app/assets/stylesheets/geoblacklight.css +0 -5
  13. data/app/components/blacklight/icons/georeferenced_component.rb +23 -0
  14. data/app/components/geoblacklight/document/download_link_component.html.erb +1 -1
  15. data/app/components/geoblacklight/document/preview_component.html.erb +0 -2
  16. data/app/components/geoblacklight/document_component.html.erb +0 -4
  17. data/app/components/geoblacklight/facets/bbox_field_component.html.erb +2 -1
  18. data/app/components/geoblacklight/georeferenced_header_badge_component.rb +16 -0
  19. data/app/components/geoblacklight/header_badge_component.html.erb +4 -2
  20. data/app/components/geoblacklight/header_badge_component.rb +1 -1
  21. data/app/components/geoblacklight/header_badges_component.html.erb +5 -0
  22. data/app/components/geoblacklight/header_badges_component.rb +34 -0
  23. data/app/components/geoblacklight/iiif_drag_drop_component.html.erb +1 -1
  24. data/app/components/geoblacklight/item_map_viewer_component.html.erb +0 -58
  25. data/app/components/geoblacklight/item_map_viewer_component.rb +19 -70
  26. data/app/components/geoblacklight/locator_map_component.rb +31 -0
  27. data/app/components/geoblacklight/login_link_component.html.erb +1 -1
  28. data/app/components/geoblacklight/login_link_component.rb +17 -1
  29. data/app/components/geoblacklight/metadata_description_markdown_component.rb +3 -9
  30. data/app/components/geoblacklight/overview_map_component.html.erb +2 -0
  31. data/app/components/geoblacklight/overview_map_component.rb +86 -0
  32. data/app/components/geoblacklight/relations/relation_component.html.erb +12 -0
  33. data/app/components/geoblacklight/relations/relation_component.rb +30 -0
  34. data/app/components/geoblacklight/relations/relations_component.html.erb +15 -0
  35. data/app/components/geoblacklight/relations/relations_component.rb +59 -0
  36. data/app/components/geoblacklight/resource_header_badge_component.rb +1 -1
  37. data/app/components/geoblacklight/search_result_component.html.erb +14 -33
  38. data/app/components/geoblacklight/search_result_component.rb +2 -14
  39. data/app/components/geoblacklight/static_map_component.rb +3 -14
  40. data/app/components/geoblacklight/truncatable_metadata_field_layout_component.html.erb +7 -0
  41. data/app/components/geoblacklight/truncatable_metadata_field_layout_component.rb +45 -0
  42. data/app/controllers/{relation_controller.rb → relations_controller.rb} +4 -2
  43. data/app/controllers/viewer_record_controller.rb +28 -0
  44. data/app/helpers/geoblacklight_helper.rb +57 -6
  45. data/app/javascript/geoblacklight/controllers/overview_map_controller.js +143 -0
  46. data/app/javascript/geoblacklight/core.js +8 -10
  47. data/app/javascript/geoblacklight/index.js +9 -12
  48. data/app/javascript/geoblacklight/initializers/field_truncation.js +62 -0
  49. data/app/javascript/geoblacklight/initializers/metadata_download.js +3 -8
  50. data/app/javascript/geoblacklight/initializers/truncation.js +7 -3
  51. data/app/javascript/geoblacklight/initializers/viewer_requests.js +61 -0
  52. data/app/javascript/geoblacklight/initializers/viewer_theme.js +28 -0
  53. data/app/models/concerns/geoblacklight/solr_document/thumbnail.rb +38 -0
  54. data/app/models/concerns/geoblacklight/solr_document.rb +2 -0
  55. data/app/models/concerns/geoblacklight/suppressed_records_search_behavior.rb +1 -1
  56. data/app/views/catalog/_document_split.html.erb +10 -10
  57. data/app/views/catalog/_home_text.html.erb +1 -1
  58. data/app/views/catalog/metadata.html.erb +1 -1
  59. data/app/views/{relation → relations}/index.html.erb +1 -1
  60. data/app/views/relations/index.json.jbuilder +9 -0
  61. data/config/importmap.rb +8 -8
  62. data/config/locales/geoblacklight.en.yml +48 -99
  63. data/geoblacklight.gemspec +3 -3
  64. data/lib/generators/geoblacklight/assets_generator.rb +2 -2
  65. data/lib/generators/geoblacklight/install_generator.rb +3 -6
  66. data/lib/generators/geoblacklight/templates/assets/customizations.css +5 -1
  67. data/lib/generators/geoblacklight/templates/catalog_controller.rb +17 -27
  68. data/lib/generators/geoblacklight/templates/settings.yml +15 -95
  69. data/lib/geoblacklight/configuration/display_note_shown_config.rb +3 -0
  70. data/lib/geoblacklight/configuration/relationship_config.rb +7 -1
  71. data/lib/geoblacklight/configuration/relationships_config.rb +15 -15
  72. data/lib/geoblacklight/configuration/settings_attributes.rb +85 -0
  73. data/lib/geoblacklight/configuration/settings_builder.rb +3 -14
  74. data/lib/geoblacklight/configuration.rb +23 -62
  75. data/lib/geoblacklight/exceptions.rb +4 -0
  76. data/lib/geoblacklight/reference.rb +0 -2
  77. data/lib/geoblacklight/references.rb +17 -5
  78. data/lib/geoblacklight/relations/ancestors.rb +12 -0
  79. data/lib/geoblacklight/relations/descendants.rb +11 -0
  80. data/lib/geoblacklight/relations/query.rb +39 -0
  81. data/lib/geoblacklight/{relation → relations}/relation_response.rb +5 -4
  82. data/lib/geoblacklight/routes/exportable.rb +2 -1
  83. data/lib/geoblacklight/version.rb +1 -1
  84. data/lib/geoblacklight/viewer_record.rb +39 -0
  85. data/lib/geoblacklight.rb +1 -1
  86. data/lib/tasks/geoblacklight.rake +1 -17
  87. data/lib/tasks/solr.rb +37 -0
  88. data/schema/readme.md +1 -1
  89. data/script/wait-for-solr +36 -0
  90. data/solr/conf/solrconfig.xml +10 -16
  91. data/spec/components/geoblacklight/document/sidebar_component_spec.rb +3 -3
  92. data/spec/components/geoblacklight/document_component_spec.rb +8 -34
  93. data/spec/components/geoblacklight/{header_icons_component_spec.rb → header_badges_component_spec.rb} +20 -2
  94. data/spec/components/geoblacklight/item_map_viewer_component_spec.rb +65 -15
  95. data/spec/components/geoblacklight/locator_map_component_spec.rb +54 -0
  96. data/spec/components/geoblacklight/login_link_component_spec.rb +20 -12
  97. data/spec/components/geoblacklight/metadata_description_markdown_component_spec.rb +1 -6
  98. data/spec/components/geoblacklight/overview_map_component_spec.rb +136 -0
  99. data/spec/components/geoblacklight/relations/relation_component_spec.rb +98 -0
  100. data/spec/components/geoblacklight/relations/relations_component_spec.rb +146 -0
  101. data/spec/components/geoblacklight/search_result_component_spec.rb +66 -39
  102. data/spec/components/geoblacklight/static_map_component_spec.rb +8 -2
  103. data/spec/components/geoblacklight/truncatable_metadata_field_layout_component_spec.rb +83 -0
  104. data/spec/controllers/catalog_controller_spec.rb +22 -7
  105. data/spec/controllers/{relation_controller_spec.rb → relations_controller_spec.rb} +1 -1
  106. data/spec/factories/user.rb +6 -1
  107. data/spec/features/axe_spec.rb +5 -3
  108. data/spec/features/home_page_spec.rb +8 -7
  109. data/spec/features/index_view_spec.rb +6 -20
  110. data/spec/features/layer_preview_spec.rb +4 -11
  111. data/spec/features/locator_map_spec.rb +31 -0
  112. data/spec/features/relations_spec.rb +22 -11
  113. data/spec/features/restricted_viewer_spec.rb +14 -0
  114. data/spec/features/search_results_map_spec.rb +89 -13
  115. data/spec/features/search_spec.rb +6 -2
  116. data/spec/features/sign_in_spec.rb +26 -0
  117. data/spec/features/tilejson_spec.rb +1 -3
  118. data/spec/features/tms_spec.rb +2 -2
  119. data/spec/features/truncated_metadata_spec.rb +77 -0
  120. data/spec/features/viewer_requests_spec.rb +40 -0
  121. data/spec/features/viewer_theme_spec.rb +51 -0
  122. data/spec/features/wmts_spec.rb +6 -6
  123. data/spec/features/xyz_spec.rb +3 -3
  124. data/spec/fixtures/solr_documents/README.md +18 -14
  125. data/spec/fixtures/solr_documents/actual-polygon1.json +22 -18
  126. data/spec/fixtures/solr_documents/b1g_wabash_child_15.json +14 -15
  127. data/spec/fixtures/solr_documents/b1g_wabash_child_16.json +14 -15
  128. data/spec/fixtures/solr_documents/b1g_wabash_child_17.json +14 -15
  129. data/spec/fixtures/solr_documents/b1g_wabash_child_18.json +14 -15
  130. data/spec/fixtures/solr_documents/b1g_wabash_parent.json +14 -15
  131. data/spec/fixtures/solr_documents/esri-dynamic-layer-single-layer.json +2 -2
  132. data/spec/fixtures/solr_documents/esri-feature-layer.json +1 -1
  133. data/spec/fixtures/solr_documents/esri-image-map-layer.json +20 -20
  134. data/spec/fixtures/solr_documents/esri-wms-layer.json +22 -24
  135. data/spec/fixtures/solr_documents/index_map_point.json +3 -3
  136. data/spec/fixtures/solr_documents/public_polygon.json +28 -0
  137. data/spec/helpers/geoblacklight_helper_spec.rb +103 -25
  138. data/spec/lib/geoblacklight/bounding_box_spec.rb +16 -0
  139. data/spec/lib/geoblacklight/configuration/relationships_config_spec.rb +121 -0
  140. data/spec/lib/geoblacklight/configuration/settings_attributes_spec.rb +113 -0
  141. data/spec/lib/geoblacklight/configuration/settings_builder_spec.rb +33 -4
  142. data/spec/lib/geoblacklight/references_spec.rb +35 -0
  143. data/spec/lib/geoblacklight/{relation → relations}/ancestors_spec.rb +17 -6
  144. data/spec/lib/geoblacklight/{relation → relations}/descendants_spec.rb +14 -7
  145. data/spec/lib/geoblacklight/{relation → relations}/relation_response_spec.rb +31 -17
  146. data/spec/lib/geoblacklight/viewer_record_spec.rb +69 -0
  147. data/spec/models/concerns/geoblacklight/solr_document/thumbnail_spec.rb +149 -0
  148. data/spec/models/concerns/geoblacklight/solr_document_spec.rb +1 -1
  149. data/spec/requests/bookmarks_spec.rb +2 -1
  150. data/spec/requests/catalog_show_spec.rb +24 -2
  151. data/spec/requests/index_view_spec.rb +50 -2
  152. data/spec/requests/missing_metadata_spec.rb +1 -1
  153. data/spec/requests/relations_spec.rb +9 -2
  154. data/spec/requests/search_results_spec.rb +6 -6
  155. data/spec/requests/viewer_record_spec.rb +37 -0
  156. data/spec/requests/viewer_requests_spec.rb +52 -0
  157. data/spec/solr_config_spec.rb +41 -0
  158. data/spec/solr_fixtures_spec.rb +23 -0
  159. data/spec/spec_helper.rb +13 -3
  160. data/spec/support/authentication.rb +37 -0
  161. data/spec/support/features/map_helpers.rb +68 -0
  162. data/spec/support/features/session_helpers.rb +18 -13
  163. data/spec/support/features/viewer_helpers.rb +20 -0
  164. data/spec/support/features.rb +4 -0
  165. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  166. data/template.rb +1 -1
  167. metadata +72 -84
  168. data/app/components/geoblacklight/accordion_component.html.erb +0 -16
  169. data/app/components/geoblacklight/accordion_component.rb +0 -15
  170. data/app/components/geoblacklight/attribute_table_component.html.erb +0 -15
  171. data/app/components/geoblacklight/attribute_table_component.rb +0 -17
  172. data/app/components/geoblacklight/header_icons_component.html.erb +0 -3
  173. data/app/components/geoblacklight/header_icons_component.rb +0 -27
  174. data/app/components/geoblacklight/index_map_inspect_component.html.erb +0 -12
  175. data/app/components/geoblacklight/index_map_inspect_component.rb +0 -15
  176. data/app/components/geoblacklight/index_map_legend_component.html.erb +0 -14
  177. data/app/components/geoblacklight/index_map_legend_component.rb +0 -24
  178. data/app/components/geoblacklight/location_leaflet_map_component.rb +0 -68
  179. data/app/components/geoblacklight/relations_component.html.erb +0 -23
  180. data/app/components/geoblacklight/relations_component.rb +0 -25
  181. data/app/components/geoblacklight/viewer_help_text_component.html.erb +0 -1
  182. data/app/components/geoblacklight/viewer_help_text_component.rb +0 -46
  183. data/app/controllers/wms_controller.rb +0 -17
  184. data/app/javascript/geoblacklight/controllers/leaflet_viewer_controller.js +0 -240
  185. data/app/javascript/geoblacklight/controllers/openlayers_viewer_controller.js +0 -74
  186. data/app/javascript/geoblacklight/controllers/search_results_controller.js +0 -50
  187. data/app/javascript/geoblacklight/initializers/popovers.js +0 -11
  188. data/app/javascript/geoblacklight/initializers/tooltips.js +0 -51
  189. data/app/javascript/geoblacklight/leaflet/basemaps.js +0 -73
  190. data/app/javascript/geoblacklight/leaflet/constants.js +0 -18
  191. data/app/javascript/geoblacklight/leaflet/controls/geosearch.js +0 -168
  192. data/app/javascript/geoblacklight/leaflet/controls/layer_opacity.js +0 -121
  193. data/app/javascript/geoblacklight/leaflet/controls/sidebar.js +0 -49
  194. data/app/javascript/geoblacklight/leaflet/controls/sleep.js +0 -101
  195. data/app/javascript/geoblacklight/leaflet/inspection.js +0 -210
  196. data/app/javascript/geoblacklight/leaflet/layer_index_map.js +0 -128
  197. data/app/javascript/geoblacklight/leaflet/layer_wmts.js +0 -57
  198. data/app/javascript/geoblacklight/leaflet/layers.js +0 -146
  199. data/app/javascript/geoblacklight/leaflet/utils.js +0 -83
  200. data/app/javascript/geoblacklight/openlayers/basemaps.js +0 -55
  201. data/app/javascript/geoblacklight/openlayers/inspection.js +0 -42
  202. data/app/javascript/geoblacklight/openlayers/layers.js +0 -44
  203. data/app/views/relation/index.json.jbuilder +0 -8
  204. data/lib/geoblacklight/configuration/layer_config.rb +0 -28
  205. data/lib/geoblacklight/configuration/leaflet_config.rb +0 -73
  206. data/lib/geoblacklight/configuration/leaflet_layers_config.rb +0 -33
  207. data/lib/geoblacklight/configuration/leaflet_sleep_config.rb +0 -20
  208. data/lib/geoblacklight/relation/ancestors.rb +0 -31
  209. data/lib/geoblacklight/relation/descendants.rb +0 -31
  210. data/lib/geoblacklight/routes/wms.rb +0 -15
  211. data/lib/geoblacklight/wms_layer/feature_info_response.rb +0 -37
  212. data/lib/geoblacklight/wms_layer.rb +0 -34
  213. data/spec/components/geoblacklight/attribute_table_component_spec.rb +0 -36
  214. data/spec/components/geoblacklight/index_map_legend_component_spec.rb +0 -29
  215. data/spec/components/geoblacklight/viewer_help_text_component_spec.rb +0 -27
  216. data/spec/controllers/wms_controller_spec.rb +0 -34
  217. data/spec/features/configurable_basemap_spec.rb +0 -40
  218. data/spec/features/full_screen_control_spec.rb +0 -15
  219. data/spec/features/layer_inspection_spec.rb +0 -12
  220. data/spec/features/layer_opacity_spec.rb +0 -16
  221. data/spec/fixtures/solr_documents/harvard_raster.json +0 -39
  222. data/spec/fixtures/solr_documents/public_polygon_mit.json +0 -23
  223. data/spec/fixtures/solr_documents/uva_slug_colon.json +0 -29
  224. data/spec/javascripts/geoblacklight_spec.js +0 -11
  225. data/spec/lib/geoblacklight/configuration/layer_config_spec.rb +0 -71
  226. data/spec/lib/geoblacklight/configuration/leaflet_config_spec.rb +0 -129
  227. data/spec/lib/geoblacklight/configuration/leaflet_layers_config_spec.rb +0 -63
  228. data/spec/lib/geoblacklight/configuration_spec.rb +0 -48
  229. data/spec/lib/geoblacklight/wms_layer/feature_info_response_spec.rb +0 -54
  230. data/spec/lib/geoblacklight/wms_layer_spec.rb +0 -115
  231. /data/app/components/geoblacklight/{location_leaflet_map_component.html.erb → locator_map_component.html.erb} +0 -0
@@ -9,11 +9,26 @@ RSpec.describe CatalogController, type: :controller do
9
9
 
10
10
  expect(description_field.component).to eq Geoblacklight::MetadataDescriptionMarkdownComponent
11
11
  end
12
+
13
+ it "uses the truncatable layout for the fields that hold long lists of values" do
14
+ fields = Geoblacklight.configuration.fields
15
+ layouts = [fields.subject, fields.theme, fields.spatial_coverage].map do |key|
16
+ described_class.blacklight_config.show_fields[key].layout_component
17
+ end
18
+
19
+ expect(layouts).to all eq Geoblacklight::TruncatableMetadataFieldLayoutComponent
20
+ end
21
+
22
+ it "leaves the component free for the fields that use the truncatable layout" do
23
+ subject_field = described_class.blacklight_config.show_fields[Geoblacklight.configuration.fields.subject]
24
+
25
+ expect(subject_field.component).to eq Blacklight::MetadataFieldComponent
26
+ end
12
27
  end
13
28
 
14
29
  describe "#web_services" do
15
30
  it "returns a document based off an id" do
16
- get :web_services, params: {id: "mit-f6rqs4ucovjk2"}
31
+ get :web_services, params: {id: "berkeley-s7pq31"}
17
32
  expect(response).to have_http_status :ok
18
33
  expect(assigns(:documents)).not_to be_nil
19
34
  end
@@ -21,17 +36,17 @@ RSpec.describe CatalogController, type: :controller do
21
36
 
22
37
  describe "#raw" do
23
38
  it "returns a JSON representation of a Solr Document" do
24
- get :raw, params: {id: "tufts-cambridgegrid100-04"}
39
+ get :raw, params: {id: "berkeley-s7st30"}
25
40
  expect(response).to have_http_status :ok
26
41
  expect(response.body).not_to be_empty
27
42
  response_values = JSON.parse(response.body)
28
43
  expect(response_values).to include "gbl_mdVersion_s" => "Aardvark"
29
- expect(response_values).to include Geoblacklight.configuration.fields.title => "100 Foot Grid Cambridge MA 2004"
30
- expect(response_values).to include Geoblacklight.configuration.fields.identifier => ["urn:geodata.tufts.edu:Tufts.CambridgeGrid100_04"]
44
+ expect(response_values).to include Geoblacklight.configuration.fields.title => "2000 Census Block Groups, Calaveras County, California, 2018"
45
+ expect(response_values).to include Geoblacklight.configuration.fields.identifier => ["https://geodata.lib.berkeley.edu/catalog/berkeley-s7st30"]
31
46
  expect(response_values).to include Geoblacklight.configuration.fields.access_rights => "Public"
32
- expect(response_values).to include Geoblacklight.configuration.fields.provider => "Tufts"
33
- expect(response_values).to include Geoblacklight.configuration.fields.id => "tufts-cambridgegrid100-04"
34
- expect(response_values).to include Geoblacklight.configuration.fields.geometry => "ENVELOPE(-71.163984,-71.052581,42.408316,42.34757)"
47
+ expect(response_values).to include Geoblacklight.configuration.fields.provider => "University of California Berkeley"
48
+ expect(response_values).to include Geoblacklight.configuration.fields.id => "berkeley-s7st30"
49
+ expect(response_values).to include Geoblacklight.configuration.fields.geometry => "ENVELOPE(-120.99553605196368,-120.01994492166297,38.50999518077548,37.83228807647538)"
35
50
  end
36
51
  end
37
52
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "spec_helper"
4
4
 
5
- RSpec.describe RelationController, type: :controller do
5
+ RSpec.describe RelationsController, type: :controller do
6
6
  describe "#index" do
7
7
  it "returns a listing of related documents for a record" do
8
8
  get :index, params: {id: "nyu_2451_34502"}
@@ -2,7 +2,12 @@
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :user do
5
- sequence(:email) { |n| "user#{n}@example.com" }
5
+ # Rails' built-in authentication calls the column email_address, where Devise calls it email
6
+ if AuthenticationHelpers.provider == :rails
7
+ sequence(:email_address) { |n| "user#{n}@example.com" }
8
+ else
9
+ sequence(:email) { |n| "user#{n}@example.com" }
10
+ end
6
11
  password { "password" }
7
12
  password_confirmation { "password" }
8
13
  end
@@ -11,7 +11,7 @@ RSpec.feature "Accessibility testing", js: true do
11
11
  end
12
12
 
13
13
  it "validates an item page" do
14
- visit solr_document_path("tufts-cambridgegrid100-04")
14
+ visit solr_document_path("berkeley-s7st30")
15
15
  expect(page).to be_accessible
16
16
  end
17
17
 
@@ -22,7 +22,8 @@ RSpec.feature "Accessibility testing", js: true do
22
22
  end
23
23
 
24
24
  it "validates an bookmarks page" do
25
- visit solr_document_path("tufts-cambridgegrid100-04")
25
+ skip_without_authentication
26
+ visit solr_document_path("berkeley-s7st30")
26
27
  click_on "Bookmark"
27
28
  visit bookmarks_path
28
29
  expect(page).to be_accessible
@@ -61,6 +62,7 @@ RSpec.feature "Accessibility testing", js: true do
61
62
  end
62
63
 
63
64
  def be_accessible
64
- be_axe_clean.excluding("#clover-viewer")
65
+ # Viewers are tested separately
66
+ be_axe_clean.excluding(".viewer")
65
67
  end
66
68
  end
@@ -9,16 +9,17 @@ RSpec.feature "Home page", js: true do # use js: true for tests which require js
9
9
 
10
10
  scenario "map should be visible" do
11
11
  within "#main-container" do
12
- expect(page).to have_css("#leaflet-viewer")
13
- expect(page).to have_css("img.leaflet-tile", visible: :all)
12
+ expect(page).to have_css("#overview-map")
14
13
  end
14
+
15
+ # The map itself is drawn inside the element
16
+ expect(find("#overview-map").shadow_root).to have_css("canvas.maplibregl-canvas")
15
17
  end
16
18
 
17
- scenario "clicking map search should create a spatial search" do
18
- within "#leaflet-viewer" do
19
- find(".search-control a").click
20
- expect(page.current_url).to match(/bbox=/)
21
- end
19
+ scenario "dragging a box over the map should create a spatial search" do
20
+ search_map_area
21
+
22
+ expect(page).to have_current_path(/bbox=/, url: true, wait: 10)
22
23
  expect(page).to have_css "#documents"
23
24
  end
24
25
  end
@@ -8,29 +8,15 @@ RSpec.feature "Index view", js: true do
8
8
  visit search_catalog_path(q: "*")
9
9
  end
10
10
 
11
- scenario "hover on record should produce bounding box on map" do
12
- # Needed to find an svg element on the page
13
- visit search_catalog_path(f: {Geoblacklight.configuration.fields.provider => ["Stanford"]})
14
- # BL7 has svg icons, so sniffing for SVG path won't return false
15
- # expect(Nokogiri::HTML.parse(page.body).css('path').length).to eq 0
16
- find(".documentHeader", match: :first).hover
17
- within("#leaflet-viewer") do
18
- expect(page).to have_css("path")
19
- end
20
- end
11
+ scenario "searching the map should retain current search parameters" do
12
+ visit "/?f[#{subject_field}][]=Population"
21
13
 
22
- scenario "click on a record area to expand collapse" do
23
- within("article", match: :first) do
24
- expect(page).to have_css(".collapsed")
25
- find("button").click
26
- expect(page).not_to have_css(".collapsed")
27
- end
28
- end
14
+ # A reader searches by dragging a box over the map, which the line of text on it says
15
+ expect(find("#overview-map").shadow_root).to have_css(".maplibregl-ctrl-geosearch")
16
+ search_map_area
29
17
 
30
- scenario "clicking map search should retain current search parameters" do
31
- visit "/?f[#{subject_field}][]=Population"
32
- find("#leaflet-viewer").double_click
33
18
  within "#appliedParams" do
19
+ expect(page).to have_content("Bounding Box", wait: 10)
34
20
  expect(page).to have_content("Subject Population")
35
21
  end
36
22
  end
@@ -3,17 +3,10 @@
3
3
  require "spec_helper"
4
4
 
5
5
  RSpec.feature "Layer preview", js: true do
6
- scenario "Restricted layer should show bounding box" do
7
- visit solr_document_path("berkeley-s76d73")
8
- within("#leaflet-viewer") do
9
- expect(page).to have_css("path")
10
- end
11
- end
6
+ # A restricted layer offers its location instead, which is spec/features/restricted_viewer_spec.rb
7
+ scenario "Public layer should be previewed as data" do
8
+ visit solr_document_path("berkeley-s7pq31")
12
9
 
13
- scenario "Public layer should show wms layer not bounding box" do
14
- visit solr_document_path("mit-f6rqs4ucovjk2")
15
- within ".leaflet-tile-pane" do
16
- expect(page).to have_css(".leaflet-layer", count: 2)
17
- end
10
+ expect(preview_tabs).to include "Web Map Service (WMS)"
18
11
  end
19
12
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.feature "locator map", js: true do
6
+ # A record with nothing previewable, so its sidebar says where it is instead
7
+ before { visit solr_document_path("princeton-1r66j405w") }
8
+
9
+ subject(:map) { map_ready("#locator-map").shadow_root }
10
+
11
+ scenario "draws where the record is" do
12
+ expect(drawn_extents("#locator-map")).to eq [[[-74.68, 40.33], [-74.63, 40.37]]]
13
+ end
14
+
15
+ # Both of these arrive with the style document, a moment after the map itself - and the globe
16
+ # survives this app setting the theme while the map is still being built
17
+ scenario "opens as a globe, and can be zoomed and flattened" do
18
+ expect(map).to have_css("button.maplibregl-ctrl-globe-enabled", wait: 10)
19
+ expect(map).to have_css("button.maplibregl-ctrl-zoom-in")
20
+ end
21
+
22
+ scenario "credits the basemap it borrowed, out of the corner it can spare" do
23
+ # CARTO and OpenStreetMap both require the credit, so it is there to open rather than gone: the
24
+ # empty class comes off once the basemap says who made it, and compact is the collapsed "i"
25
+ expect(map).to have_css(".maplibregl-ctrl-attrib.maplibregl-compact:not(.maplibregl-attrib-empty)", wait: 10)
26
+ end
27
+
28
+ scenario "has nothing to search, because a locator answers one question" do
29
+ expect(map).to have_no_css(".maplibregl-ctrl-geosearch")
30
+ end
31
+ end
@@ -5,22 +5,33 @@ require "spec_helper"
5
5
  RSpec.feature "Display related documents" do
6
6
  scenario "Record with relations should render widget in catalog#show", js: true do
7
7
  visit solr_document_path("nyu_2451_34635")
8
- expect(page).to have_css(".card.relations", visible: :all)
9
- expect(page).to have_css("div.card-header", text: "Derived records...", visible: :all)
8
+ expect(page).to have_css(".card.relations", visible: :all, wait: 10)
9
+ expect(page).to have_css("div.card-header", text: "Source of", visible: :all, wait: 10)
10
10
  end
11
11
 
12
12
  scenario "Record without relations should not render widget in catalog#show", js: true do
13
- visit solr_document_path("harvard-g7064-s2-1834-k3")
14
- expect(page).to have_no_css(".card.relations")
13
+ # Public polygon record, which carries none of the relationship fields
14
+ visit solr_document_path("berkeley-s7pq31")
15
+
16
+ # The card is rendered inside a lazily-fetched turbo-frame, so wait for the frame to
17
+ # report itself complete before asserting absence. A negative Capybara matcher is
18
+ # satisfied the instant the element is missing, so without this the assertion passes
19
+ # at t=0 for every record - including ones that do have relations.
20
+ expect(page).to have_css("turbo-frame#relations[complete]", visible: :all, wait: 10)
21
+ expect(page).to have_no_css(".card.relations", visible: :all)
15
22
  end
16
23
 
17
24
  scenario "Relationship browse link returns relationship-scoped results", js: true do
18
25
  # Wabash Topo parent record
19
26
  visit solr_document_path("eee6150b-ce2f-4837-9d17-ce72a0c1c26f")
20
27
 
21
- expect(page).to have_content(:all, "Has part...")
22
- expect(page).to have_link("Browse all 4 records...", visible: :all)
23
- click_link("Browse all 4 records...", visible: :all)
28
+ expect(page).to have_content(:all, "Has 4 parts", wait: 10)
29
+ expect(page).to have_link("Browse all 4 parts of this item", visible: :all, wait: 10)
30
+
31
+ # Follow the link's href directly rather than clicking it - the sidebar is still drawing
32
+ # asynchronously at this point, which can shift the link out from under a real click.
33
+ browse_all_href = find_link("Browse all 4 parts of this item", visible: :all)[:href]
34
+ visit browse_all_href
24
35
 
25
36
  expect(page).not_to have_content("No results found for your search")
26
37
  end
@@ -28,24 +39,24 @@ RSpec.feature "Display related documents" do
28
39
  scenario "Record with dct_isPartOf_sm value(s) should link to relations", js: true do
29
40
  # All Relationships
30
41
  visit solr_document_path("all-relationships")
31
- expect(page).to have_content(:all, "Is part of...")
42
+ expect(page).to have_content(:all, "Part of", wait: 10)
32
43
  end
33
44
 
34
45
  scenario "Record pointed at by a parent with dct_isPartOf_sm value(s) should link back", js: true do
35
46
  # The Related Record
36
47
  visit solr_document_path("the-related-record")
37
- expect(page).to have_content(:all, "Has part...")
48
+ expect(page).to have_content(:all, "Has part", wait: 10)
38
49
  end
39
50
 
40
51
  scenario "Record with pcdm_memberOf_sm value(s) should link to relations", js: true do
41
52
  # All Relationships
42
53
  visit solr_document_path("all-relationships")
43
- expect(page).to have_content(:all, "Belongs to collection...")
54
+ expect(page).to have_content(:all, "In collection", wait: 10)
44
55
  end
45
56
 
46
57
  scenario "Record pointed at by a parent with pcdm_memberOf_sm value(s) should link back", js: true do
47
58
  # The Related Record
48
59
  visit solr_document_path("the-related-record")
49
- expect(page).to have_content(:all, "Collection records...")
60
+ expect(page).to have_content(:all, "Contains", wait: 10)
50
61
  end
51
62
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.feature "Restricted item viewer", js: true do
6
+ scenario "shows where the layer is rather than failing to load it" do
7
+ visit solr_document_path("stanford-dp018hs9766")
8
+
9
+ # The viewer was handed a record with no service references, so the only preview it can offer
10
+ # is the record's own extent
11
+ previews = find("ogm-viewer").shadow_root.find("ogm-previews", visible: :all)
12
+ expect(previews.shadow_root).to have_css("wa-tab", text: "Location", visible: :all)
13
+ end
14
+ end
@@ -3,19 +3,95 @@
3
3
  require "spec_helper"
4
4
 
5
5
  RSpec.feature "search results map", js: true do
6
+ before { visit search_catalog_path(q: "Minneapolis") }
7
+
8
+ scenario "draws where each result is, numbered the way the list beside it is" do
9
+ expect(drawn_extents.count).to eq page.all(".document").count
10
+
11
+ # The map counts from one over everything it was given, and the counter beside a result counts
12
+ # from the start of the whole result set - so on the first page of results the two agree
13
+ expect(page.all(".document").map { |result| result["data-document-counter"] })
14
+ .to eq (1..drawn_extents.count).map(&:to_s)
15
+ end
16
+
6
17
  scenario "view is scoped to Twin Cities metro area" do
7
- visit search_catalog_path(q: "Minneapolis")
8
- expect(page).to have_css "#leaflet-viewer"
9
- sleep 1
10
-
11
- bbox = page.find("#leaflet-viewer")["data-bounds"]
12
-
13
- # Example bbox for q: Minneapolis
14
- # "-94.537353515625,44.004669106432225,-92.208251953125,45.87088761346192"
15
- left, bottom, right, top = bbox.split(",")
16
- expect(left.to_f).to be_within(1).of(-94)
17
- expect(bottom.to_f).to be_within(1).of(44)
18
- expect(right.to_f).to be_within(1).of(-92)
19
- expect(top.to_f).to be_within(1).of(45)
18
+ # Example extent for q: Minneapolis
19
+ # [[-94.012, 44.471], [-92.732, 45.415]]
20
+ (west, south), (east, north) = drawn_extents.first
21
+
22
+ expect(west).to be_within(1).of(-94)
23
+ expect(south).to be_within(1).of(44)
24
+ expect(east).to be_within(1).of(-92)
25
+ expect(north).to be_within(1).of(45)
26
+ end
27
+
28
+ scenario "comes back knowing the area the reader searched" do
29
+ # The line of text saying how to search goes up with the map
30
+ expect(find("#overview-map").shadow_root).to have_css(".maplibregl-ctrl-geosearch")
31
+
32
+ search_map_area
33
+
34
+ within "#appliedParams" do
35
+ expect(page).to have_content("Bounding Box", wait: 10)
36
+ end
37
+
38
+ # A map that draws, rather than an empty box
39
+ expect(find("#overview-map").shadow_root).to have_css("canvas.maplibregl-canvas")
40
+
41
+ # ...and one that has been told what the results were narrowed to, which is what it points
42
+ # itself at: the results themselves can't do that job, because a bbox query matches everything
43
+ # that *intersects* the box and a single continent-wide dataset among them would frame a continent.
44
+ # Read as a property rather than the search-bounds attribute: the map is carried over this search
45
+ # rather than rebuilt, so its attribute is frozen at whatever it was on the first render, and it's
46
+ # the live property the controller corrects on reconnect that the map actually goes by.
47
+ expect(page.evaluate_script("document.querySelector('#overview-map').searchBounds")).to eq searched_bbox
48
+ end
49
+
50
+ scenario "keeps the same map, canvas and all, rather than rebuilding it" do
51
+ map = map_ready
52
+ canvas = map.shadow_root.find("canvas.maplibregl-canvas", visible: :all)
53
+ page.execute_script("arguments[0].dataset.probe = 'kept-map'", map)
54
+ page.execute_script("arguments[0].dataset.probe = 'kept-canvas'", canvas)
55
+
56
+ search_map_area
57
+
58
+ within "#appliedParams" do
59
+ expect(page).to have_content("Bounding Box", wait: 10)
60
+ end
61
+
62
+ # A freshly built element or WebGL canvas would start without these - they are set by hand above,
63
+ # not by the server or component. Keeping both is what avoids another map load and tile fetch.
64
+ carried = find("#overview-map")
65
+ expect(carried["data-probe"]).to eq "kept-map"
66
+ expect(carried.shadow_root.find("canvas.maplibregl-canvas", visible: :all)["data-probe"]).to eq "kept-canvas"
67
+
68
+ # And it's been given the narrowed results to draw, not left showing what it had before
69
+ expect(drawn_extents.count).to eq page.all(".document").count
70
+ end
71
+
72
+ describe "pointing at a result" do
73
+ let(:result) { page.all(".document").first }
74
+ let(:layer_id) { result["data-map-id"] }
75
+
76
+ scenario "from the list tells the map which one it is" do
77
+ map_ready
78
+ result.hover
79
+
80
+ expect(page.evaluate_script("document.querySelector('#overview-map').highlighted")).to eq layer_id
81
+ end
82
+
83
+ scenario "on the map marks its row in the list" do
84
+ map = map_ready
85
+
86
+ # As the map reports a reader's pointer landing on a number. Sent here rather than pointed at,
87
+ # because the numbers are drawn into a canvas inside the map's own shadow root, and where each
88
+ # of them lands on screen is the map's business.
89
+ page.execute_script(<<~JS, map, layer_id)
90
+ const [map, id] = arguments
91
+ map.dispatchEvent(new CustomEvent("highlightChange", { detail: { place: 1, id } }))
92
+ JS
93
+
94
+ expect(result[:class]).to include "highlighted"
95
+ end
20
96
  end
21
97
  end
@@ -6,11 +6,15 @@ RSpec.feature "Search" do
6
6
  scenario "When searching child records from a parent record, supressed records are not hidden", js: true do
7
7
  visit "/catalog/princeton-1r66j405w"
8
8
 
9
- within(".card.relations.relationship-source_descendants", visible: :all) do
9
+ within(".card.relations", visible: :all) do
10
10
  expect(page).to have_link(href: /f%5Bdct_source_sm%5D/, visible: :all)
11
11
  end
12
12
 
13
- click_link "Browse all 4 records...", visible: :all
13
+ # The sidebar holds a map of where this record is, and it arrives after the page does - so the
14
+ # link below is still moving until it has been drawn
15
+ map_ready("#locator-map")
16
+
17
+ click_link "Browse all 4 items sourced from this item", visible: :all
14
18
  expect(page).to have_css ".document", count: 4
15
19
  end
16
20
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.feature "Signing in to see a restricted record" do
6
+ let(:restricted) { "stanford-dp018hs9766" }
7
+
8
+ scenario "brings the reader back to the record once they're signed in" do
9
+ skip_without_authentication
10
+ visit solr_document_path(restricted)
11
+ click_link "Login to View and Download"
12
+ fill_in_sign_in_form FactoryBot.create(:user)
13
+
14
+ expect(page).to have_current_path(solr_document_path(restricted))
15
+ expect(page).to have_link "Log Out"
16
+ expect(page).to have_no_link "Login to View and Download"
17
+ end
18
+
19
+ scenario "is not offered when the app has no authentication" do
20
+ skip "the test app has authentication" if AuthenticationHelpers.provider
21
+ visit solr_document_path(restricted)
22
+
23
+ expect(page).to have_css "h1", text: "Elkhorn Slough"
24
+ expect(page).to have_no_link "Login to View and Download"
25
+ end
26
+ end
@@ -18,8 +18,6 @@ RSpec.feature "tilejson layer" do
18
18
 
19
19
  visit solr_document_path("princeton-fk4544658v-tilejson")
20
20
 
21
- expect(page).to have_css ".leaflet-control-zoom", visible: :visible
22
- expect(page).to have_css "div[data-leaflet-viewer-protocol-value='Tilejson']"
23
- expect(page).to have_css "div[data-leaflet-viewer-url-value='https://map-tiles-staging.princeton.edu/2a91d82c541c426cb787cc62afe8f248/mosaicjson/tilejson.json']"
21
+ expect(preview_tabs).to include "TileJSON"
24
22
  end
25
23
  end
@@ -5,7 +5,7 @@ require "spec_helper"
5
5
  RSpec.feature "tms layer" do
6
6
  scenario "displays tms layer", js: true do
7
7
  visit solr_document_path("cugir-007957")
8
- expect(page).to have_css ".leaflet-control-zoom"
9
- expect(page).to have_css "img[src*='cugir.library.cornell.edu']", visible: :all
8
+
9
+ expect(preview_tabs).to include "Tiled Map Service (TMS)"
10
10
  end
11
11
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.feature "Metadata fields that limit their values" do
6
+ let(:group) { "div.truncate-field:has(dt.blacklight-dct_subject_sm)" }
7
+ let(:read_more) { find("#{group} > dd.read-more-slot button") }
8
+
9
+ # Princeton record carrying nine subject values, four more than the five it shows in full
10
+ scenario "The values past the limit are hidden until the reader asks for them", js: true do
11
+ visit solr_document_path("princeton-dc7h14b252v")
12
+
13
+ subjects = find(group)
14
+
15
+ # Every value keeps its own dd. The value at the limit is clipped to show that the list
16
+ # carries on; the ones after it are taken out of view entirely.
17
+ expect(subjects).to have_css("dd:not(.read-more-slot)", count: 9, visible: :all)
18
+ expect(subjects).to have_css("dd.truncate-preview", count: 1, visible: :all)
19
+ expect(subjects).to have_css("dd.visually-hidden", count: 3, visible: :all)
20
+
21
+ # The text assertions are scoped to the field: the viewer's own metadata panel lists
22
+ # every subject too, so a page-wide matcher would race with the viewer loading.
23
+ expect(subjects).to have_no_text("Physical maps")
24
+
25
+ read_more.click
26
+
27
+ expect(subjects).to have_no_css("dd.visually-hidden", visible: :all)
28
+ expect(subjects).to have_no_css("dd.truncate-preview", visible: :all)
29
+ expect(subjects).to have_text("Physical maps")
30
+ expect(read_more).to have_text("Close")
31
+
32
+ read_more.click
33
+
34
+ expect(subjects).to have_css("dd.visually-hidden", count: 3, visible: :all)
35
+ expect(subjects).to have_css("dd.truncate-preview", count: 1, visible: :all)
36
+ expect(read_more).to have_text("Read more")
37
+ end
38
+
39
+ scenario "The clipped value fades out, the way a clamped description does", js: true do
40
+ visit solr_document_path("princeton-dc7h14b252v")
41
+
42
+ preview = find("#{group} > dd.truncate-preview", visible: :all)
43
+ expect(preview.evaluate_script("getComputedStyle(this, '::after').backgroundImage")).to include "linear-gradient"
44
+
45
+ # A shade under one line tall, so the value reads as cut off rather than as its own entry
46
+ line_height = preview.evaluate_script("parseFloat(getComputedStyle(this).lineHeight)")
47
+ expect(preview.evaluate_script("this.getBoundingClientRect().height")).to be < line_height
48
+
49
+ # The gradient covers the value, so it must not swallow clicks on the link beneath it
50
+ expect(preview.evaluate_script("getComputedStyle(this, '::after').pointerEvents")).to eq "none"
51
+ end
52
+
53
+ scenario "The hidden values stay available to assistive technology", js: true do
54
+ visit solr_document_path("princeton-dc7h14b252v")
55
+
56
+ # visually-hidden leaves the values in the accessibility tree, so the button is of no use
57
+ # to assistive technology and says so rather than promising something it cannot deliver
58
+ expect(read_more[:"aria-disabled"]).to eq "true"
59
+ expect(read_more[:"aria-label"]).to include "assistive technology"
60
+
61
+ hidden = all("#{group} > dd.visually-hidden", visible: :all).last
62
+ expect(hidden.evaluate_script("getComputedStyle(this).display")).not_to eq "none"
63
+ expect(hidden.evaluate_script("getComputedStyle(this).visibility")).not_to eq "hidden"
64
+ end
65
+
66
+ scenario "Fields short enough to fit are left alone", js: true do
67
+ visit solr_document_path("princeton-dc7h14b252v")
68
+
69
+ # Wait for the initializer to have run before asserting that it skipped this field
70
+ expect(page).to have_css("#{group} > dd.read-more-slot button")
71
+
72
+ spatial = "div.truncate-field:has(dt.blacklight-dct_spatial_sm)"
73
+ expect(page).to have_no_css("#{spatial} > dd.read-more-slot button")
74
+ expect(page).to have_no_css("#{spatial} > dd.visually-hidden", visible: :all)
75
+ expect(page).to have_no_css("#{spatial} > dd.truncate-preview", visible: :all)
76
+ end
77
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.feature "Viewer requests", js: true do
6
+ # What the viewer would ask about while previewing this record: the restricted file itself, and
7
+ # the basemap it draws underneath, which is an unrelated origin
8
+ let(:probe) do
9
+ <<~JS
10
+ (() => {
11
+ const viewer = document.querySelector("ogm-viewer")
12
+ if (typeof viewer.requestTransform !== "function") return null
13
+ return {
14
+ service: viewer.requestTransform("https://stacks.stanford.edu/file/druid:dp018hs9766/es2005_1m_10color_cog.tif", "tile"),
15
+ basemap: viewer.requestTransform("https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json", "metadata"),
16
+ }
17
+ })()
18
+ JS
19
+ end
20
+
21
+ around do |example|
22
+ configured = Geoblacklight.configuration.restricted_origins
23
+ Geoblacklight.configuration.restricted_origins = ["https://stacks.stanford.edu/"]
24
+ example.run
25
+ Geoblacklight.configuration.restricted_origins = configured
26
+ end
27
+
28
+ scenario "a signed-in reader's requests carry cookies to the configured service, and nowhere else" do
29
+ sign_in
30
+ visit solr_document_path("stanford-dp018hs9766")
31
+
32
+ # The transform is set once the initializers run, which is a moment after the page arrives
33
+ transform = page.document.synchronize(5) do
34
+ page.evaluate_script(probe) || raise(Capybara::ElementNotFound)
35
+ end
36
+
37
+ expect(transform["service"]).to eq("credentials" => "include")
38
+ expect(transform["basemap"]).to be_nil
39
+ end
40
+ end