@@ -228,4 +228,81 @@ def test_does_not_render_input_events_when_show_clear_button_is_not_set
228228 )
229229 assert_no_selector ( ".FormControl-input-trailingAction[data-action=\" click:primer-text-field#clearContents\" ]" )
230230 end
231+
232+ def test_renders_collapsed_search
233+ render_inline ( Primer ::OpenProject ::SubHeader . new ( collapsed_search : true ) ) do |component |
234+ component . with_filter_input ( name : "filter" , label : "Filter" )
235+ end
236+
237+ assert_selector ( ".SubHeader" )
238+ # Trigger is rendered and wired to expand
239+ assert_selector ( "[data-action='click:sub-header#expandFilterInput']" )
240+ # Filter container starts hidden on all screen sizes (d-none, no d-sm-flex)
241+ assert_selector ( ".SubHeader-filterContainer.d-none" )
242+ assert_no_selector ( ".SubHeader-filterContainer.d-sm-flex" )
243+ end
244+
245+ def test_collapsed_search_trigger_visible_on_all_screen_sizes
246+ render_inline ( Primer ::OpenProject ::SubHeader . new ( collapsed_search : true ) ) do |component |
247+ component . with_filter_input ( name : "filter" , label : "Filter" )
248+ end
249+
250+ # Without collapsed_search, the trigger has d-sm-none (hidden on desktop).
251+ # With collapsed_search, it must not have d-sm-none.
252+ assert_no_selector ( "[data-action='click:sub-header#expandFilterInput'].d-sm-none" )
253+ end
254+
255+ def test_default_search_trigger_hidden_on_desktop
256+ render_inline ( Primer ::OpenProject ::SubHeader . new ) do |component |
257+ component . with_filter_input ( name : "filter" , label : "Filter" )
258+ end
259+
260+ # Without collapsed_search the trigger is mobile-only (d-sm-none)
261+ assert_selector ( "[data-action='click:sub-header#expandFilterInput'].d-sm-none" )
262+ # The mobile icon button must carry SubHeader-hiddenOnExpand so CSS hides it when search expands
263+ assert_selector ( ".SubHeader-leftPane .SubHeader-hiddenOnExpand.Button--iconOnly" )
264+ end
265+
266+ def test_renders_quick_filters
267+ render_inline ( Primer ::OpenProject ::SubHeader . new ) do |component |
268+ component . with_filter_input ( name : "filter" , label : "Filter" )
269+ component . with_filter_button { "Filter" }
270+ component . with_quick_filter { "<span class='MyQuickFilter'>Status</span>" . html_safe }
271+ component . with_quick_filter { "<span class='MyQuickFilter'>Assignee</span>" . html_safe }
272+ end
273+
274+ assert_selector ( ".SubHeader-leftPane .MyQuickFilter" , count : 2 )
275+ end
276+
277+ def test_quick_filters_are_hidden_on_mobile
278+ render_inline ( Primer ::OpenProject ::SubHeader . new ) do |component |
279+ component . with_filter_button { "Filter" }
280+ component . with_quick_filter { "<span class='MyQuickFilter'>Status</span>" . html_safe }
281+ end
282+
283+ # Each quick_filter wrapper has d-none d-sm-flex (hidden on mobile, visible on desktop)
284+ assert_selector ( ".d-none.d-sm-flex .MyQuickFilter" )
285+ end
286+
287+ def test_quick_filters_require_filter_button
288+ err = assert_raises ArgumentError do
289+ render_inline ( Primer ::OpenProject ::SubHeader . new ) do |component |
290+ component . with_filter_input ( name : "filter" , label : "Filter" )
291+ component . with_quick_filter { "Status" }
292+ end
293+ end
294+
295+ assert_equal "You must provide a filter_button when using quick_filters." , err . message
296+ end
297+
298+ def test_quick_filters_maximum_is_five
299+ err = assert_raises ArgumentError do
300+ render_inline ( Primer ::OpenProject ::SubHeader . new ) do |component |
301+ component . with_filter_button { "Filter" }
302+ 6 . times { |i | component . with_quick_filter { "Filter #{ i } " } }
303+ end
304+ end
305+
306+ assert_equal "SubHeader supports a maximum of 5 quick_filters, got 6." , err . message
307+ end
231308end
0 commit comments