@@ -63,6 +63,10 @@ def mock_primo_search_all_tab
6363 end
6464
6565 def mock_primo_search_with_hits ( total_hits )
66+ # Use when the test needs to control the simulated Primo hit count, e.g., pagination
67+ # boundary tests or UI behavior that reacts to total result numbers. Always returns
68+ # 10 sample documents regardless of `total_hits`; only the reported total varies.
69+ # For tests that don't care about hit counts, prefer `mock_primo_search_success`.
6670 sample_docs = ( 1 ..10 ) . map do |i |
6771 {
6872 title : "Sample Primo Document Title #{ i } " ,
@@ -86,11 +90,13 @@ def mock_primo_search_with_hits(total_hits)
8690 end
8791
8892 def mock_timdex_search_success
89- # Mock the TIMDEX GraphQL client to avoid external API calls (single call)
93+ # Use for standard single-tab TIMDEX tests that don't inspect the query variables
94+ # passed to the GraphQL client. Sets `expects(:query)` without `.with(...)`, so
95+ # Mocha only verifies the call count, not the arguments.
9096 #
91- # NOTE: As with Primo, this helper assumes a single TIMDEX invocation .
92- # Tests exercising the 'all' tab should use `mock_timdex_search_all_tab`
93- # which allows multiple calls .
97+ # - For the 'all' tab (multiple TIMDEX calls): use `mock_timdex_search_all_tab` .
98+ # - For tests asserting on query variables (e.g., feature flags): use
99+ # `build_timdex_mock_response` and set the expectation with `.with(...)` yourself .
94100 sample_result = {
95101 'api' => 'timdex' ,
96102 'title' => 'Sample TIMDEX Document Title' ,
@@ -134,11 +140,10 @@ def mock_timdex_search_success
134140 end
135141
136142 def mock_timdex_search_all_tab
137- # Mock the TIMDEX GraphQL client for the all tab (multiple calls)
138- #
139- # This helper is intentionally separate from `mock_timdex_search_success`
140- # because the merged-search orchestration can invoke TIMDEX multiple
141- # times. The helper therefore uses `at_least_once` on the expectation.
143+ # Use for tests exercising the 'all' tab, where `MergedSearchService` may invoke
144+ # TIMDEX multiple times. Relaxes the expectation to `at_least_once` to accommodate
145+ # that orchestration. For single-tab TIMDEX tests, prefer `mock_timdex_search_success`
146+ # so unexpected extra calls cause a failure rather than passing silently.
142147 sample_result = {
143148 'api' => 'timdex' ,
144149 'title' => 'Sample TIMDEX Document Title' ,
@@ -182,6 +187,11 @@ def mock_timdex_search_all_tab
182187 end
183188
184189 def mock_timdex_search_with_hits ( total_hits )
190+ # Use when the test needs to control the simulated TIMDEX hit count, e.g., pagination
191+ # threshold or no-results-message tests. Always returns 10 sample documents regardless
192+ # of `total_hits`; only the reported total varies. Unlike the other TIMDEX helpers,
193+ # this one also mocks `NormalizeTimdexResults` explicitly. For tests that don't care
194+ # about hit counts, prefer `mock_timdex_search_success`.
185195 sample_results = ( 1 ..10 ) . map do |i |
186196 {
187197 'title' => "Sample TIMDEX Document Title #{ i } " ,
@@ -225,6 +235,54 @@ def mock_timdex_search_with_hits(total_hits)
225235 NormalizeTimdexResults . expects ( :new ) . returns ( mock_normalizer ) . at_least_once
226236 end
227237
238+ def build_timdex_mock_response
239+ # Use when a test needs to assert on the variables passed to `TimdexBase::Client.query`
240+ # (e.g., verifying a feature flag sets the correct query variable). Returns a fully
241+ # stubbed response object but intentionally does NOT set any expectation on
242+ # `TimdexBase::Client`. The caller is responsible for setting the expectation:
243+ #
244+ # mock_response = build_timdex_mock_response
245+ # TimdexBase::Client.expects(:query).with(TimdexSearch::BaseQuery,
246+ # has_entry(:variables, has_entry(:someVar, expected_value))).returns(mock_response)
247+ #
248+ # The other TIMDEX helpers (`mock_timdex_search_success`, etc.) set the expectation
249+ # themselves without `.with(...)`, so they cannot be used when argument assertions
250+ # are needed — Mocha would end up with two conflicting expectations on the same method.
251+ sample_result = {
252+ 'api' => 'timdex' ,
253+ 'title' => 'Sample TIMDEX Document Title' ,
254+ 'timdexRecordId' => 'sample-record-123' ,
255+ 'contentType' => [ 'Article' ] ,
256+ 'dates' => [ { 'kind' => 'Publication date' , 'value' => '2023' } ] ,
257+ 'contributors' => [ { 'value' => 'Foo Barston' , 'kind' => 'Creator' } ] ,
258+ 'sourceLink' => 'https://example.com/record'
259+ }
260+
261+ mock_response = mock ( 'timdex_response' )
262+ mock_errors = mock ( 'timdex_errors' )
263+ mock_errors . stubs ( :details ) . returns ( { } )
264+ mock_errors . stubs ( :to_h ) . returns ( { } )
265+ mock_response . stubs ( :errors ) . returns ( mock_errors )
266+
267+ mock_data = mock ( 'timdex_data' )
268+ mock_search = mock ( 'timdex_search' )
269+ mock_search . stubs ( :to_h ) . returns ( {
270+ 'hits' => 1 ,
271+ 'aggregations' => { } ,
272+ 'records' => [ sample_result ]
273+ } )
274+ mock_data . stubs ( :search ) . returns ( mock_search )
275+ mock_data . stubs ( :to_h ) . returns ( {
276+ 'search' => {
277+ 'hits' => 1 ,
278+ 'aggregations' => { } ,
279+ 'records' => [ sample_result ]
280+ }
281+ } )
282+ mock_response . stubs ( :data ) . returns ( mock_data )
283+ mock_response
284+ end
285+
228286 test 'index shows basic search form by default' do
229287 get '/'
230288 assert_response :success
@@ -1220,4 +1278,29 @@ def source_filter_count(controller)
12201278 # Should not be redirected to Turnstile (doesn't hit SearchController)
12211279 assert_response :success
12221280 end
1281+
1282+ # FEATURE_GLOBAL_SCORING tests
1283+ test 'timdex query passes useGlobalScoring: false when FEATURE_GLOBAL_SCORING is disabled' do
1284+ mock_response = build_timdex_mock_response
1285+ TimdexBase ::Client . expects ( :query ) . with (
1286+ TimdexSearch ::BaseQuery ,
1287+ has_entry ( :variables , has_entry ( :useGlobalScoring , false ) )
1288+ ) . returns ( mock_response )
1289+
1290+ get '/results?q=data&tab=timdex'
1291+ assert_response :success
1292+ end
1293+
1294+ test 'timdex query passes useGlobalScoring: true when FEATURE_GLOBAL_SCORING is enabled' do
1295+ mock_response = build_timdex_mock_response
1296+ ClimateControl . modify ( FEATURE_GLOBAL_SCORING : 'true' ) do
1297+ TimdexBase ::Client . expects ( :query ) . with (
1298+ TimdexSearch ::BaseQuery ,
1299+ has_entry ( :variables , has_entry ( :useGlobalScoring , true ) )
1300+ ) . returns ( mock_response )
1301+
1302+ get '/results?q=data&tab=timdex'
1303+ assert_response :success
1304+ end
1305+ end
12231306end
0 commit comments