From 3cfe1e6e95bb074327d9c6c15680070614c5d174 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Thu, 27 Aug 2026 13:04:54 -0400 Subject: [PATCH 1/5] Tests to confirm current behavior --- test/controllers/search_controller_test.rb | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/controllers/search_controller_test.rb b/test/controllers/search_controller_test.rb index 0062ed31..dd0545c8 100644 --- a/test/controllers/search_controller_test.rb +++ b/test/controllers/search_controller_test.rb @@ -1264,6 +1264,10 @@ def source_filter_count(controller) get "/results?q=test&format=json&format_token=#{secret_value}", headers: { 'HTTP_USER_AGENT' => quepid_ua } assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type + response_json = JSON.parse(response.body) + assert_equal ['results', 'pagination', 'errors'], response_json.keys + assert_instance_of Array, response_json["results"] + assert_instance_of Integer, response_json["pagination"]["hits"] end end @@ -1276,6 +1280,25 @@ def source_filter_count(controller) get "/results?q=test&format=json&format_token=#{secret_value}", headers: { 'HTTP_USER_AGENT' => quepid_ua } assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type + response_json = JSON.parse(response.body) + assert_equal ['results', 'pagination', 'errors'], response_json.keys + assert_instance_of Array, response_json["results"] + assert_instance_of Integer, response_json["pagination"]["hits"] + end + end + + test 'results can be returned in JSON format when env is set while load-more pagination is enabled' do + secret_value = 'sooper_sekret' + quepid_ua = 'Quepid/1.0 (Web Scraper)' + ClimateControl.modify(FORMAT_TOKEN: secret_value, FEATURE_PAGINATION_LOAD_MORE: 'true') do + mock_timdex_search_with_hits(10) + get "/results?q=test&format=json&format_token=#{secret_value}", headers: { 'HTTP_USER_AGENT' => quepid_ua } + assert_response :success + assert_equal 'application/json; charset=utf-8', response.content_type + response_json = JSON.parse(response.body) + assert_equal ['results', 'pagination', 'errors'], response_json.keys + assert_instance_of Array, response_json["results"] + assert_instance_of Integer, response_json["pagination"]["hits"] end end From 439fd2d715aae96d96fa38da0b513cf8e0e39a33 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Thu, 27 Aug 2026 13:05:56 -0400 Subject: [PATCH 2/5] Fix for behavior --- app/controllers/search_controller.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index c0cf0f62..1a361886 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -45,7 +45,7 @@ def results # Render the response in HTML or JSON format respond_to do |format| - format.json { render json: { results: @results, pagination: @pagination, errors: @errors } } + format.json { render json: { results: @results, pagination: hit_count, errors: @errors } } format.turbo_stream { render :results } format.html { render :results } end @@ -53,6 +53,13 @@ def results private + # This returns the total result count from whichever instance variable is present + def hit_count + return @pagination unless pagination_load_more_enabled? + + { hits: @load_more[:total_hits] } + end + # Sleep to simulate latency for testing loading indicators when responses are fast def sleep_if_too_fast start_time = Time.now From 64e780aa56c7c83ba6c1d989ec64de14c7d0021e Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Thu, 27 Aug 2026 17:16:33 -0400 Subject: [PATCH 3/5] qlty check feedback --- test/controllers/search_controller_test.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/controllers/search_controller_test.rb b/test/controllers/search_controller_test.rb index dd0545c8..245bbb29 100644 --- a/test/controllers/search_controller_test.rb +++ b/test/controllers/search_controller_test.rb @@ -1265,9 +1265,9 @@ def source_filter_count(controller) assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type response_json = JSON.parse(response.body) - assert_equal ['results', 'pagination', 'errors'], response_json.keys - assert_instance_of Array, response_json["results"] - assert_instance_of Integer, response_json["pagination"]["hits"] + assert_equal %w[results pagination errors], response_json.keys + assert_instance_of Array, response_json['results'] + assert_instance_of Integer, response_json['pagination']['hits'] end end @@ -1281,9 +1281,9 @@ def source_filter_count(controller) assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type response_json = JSON.parse(response.body) - assert_equal ['results', 'pagination', 'errors'], response_json.keys - assert_instance_of Array, response_json["results"] - assert_instance_of Integer, response_json["pagination"]["hits"] + assert_equal %w[results pagination errors], response_json.keys + assert_instance_of Array, response_json['results'] + assert_instance_of Integer, response_json['pagination']['hits'] end end @@ -1296,9 +1296,9 @@ def source_filter_count(controller) assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type response_json = JSON.parse(response.body) - assert_equal ['results', 'pagination', 'errors'], response_json.keys - assert_instance_of Array, response_json["results"] - assert_instance_of Integer, response_json["pagination"]["hits"] + assert_equal %w[results pagination errors], response_json.keys + assert_instance_of Array, response_json['results'] + assert_instance_of Integer, response_json['pagination']['hits'] end end From 81a79fe3610e652741adcb2f17e4c0fa47c42b90 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Fri, 28 Aug 2026 11:28:46 -0400 Subject: [PATCH 4/5] Respond to copilot feedback This is not the agent's suggested change, but it does respond to what I think the agent's criticism was - inconsistent shape in the response, and a lack of robustness to different data conditions. My response is to focus on the one value that Quepid needs - the number of hits - and strip out all the other parameters that could be found between the @pagination and @load_more instance variables. The new hit_count method is also more robust to nulls by using the &.[]() syntax, and falls back to 0 if a value cannot be extracted. --- app/controllers/search_controller.rb | 10 ++++++---- test/controllers/search_controller_test.rb | 12 ++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 1a361886..58799bc6 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -45,7 +45,7 @@ def results # Render the response in HTML or JSON format respond_to do |format| - format.json { render json: { results: @results, pagination: hit_count, errors: @errors } } + format.json { render json: { results: @results, hits: hit_count, errors: @errors } } format.turbo_stream { render :results } format.html { render :results } end @@ -55,9 +55,11 @@ def results # This returns the total result count from whichever instance variable is present def hit_count - return @pagination unless pagination_load_more_enabled? - - { hits: @load_more[:total_hits] } + if @pagination_load_more_enabled + @load_more&.[](:total_hits) || 0 + else + @pagination&.[](:hits) || 0 + end end # Sleep to simulate latency for testing loading indicators when responses are fast diff --git a/test/controllers/search_controller_test.rb b/test/controllers/search_controller_test.rb index 245bbb29..eff066b4 100644 --- a/test/controllers/search_controller_test.rb +++ b/test/controllers/search_controller_test.rb @@ -1265,9 +1265,9 @@ def source_filter_count(controller) assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type response_json = JSON.parse(response.body) - assert_equal %w[results pagination errors], response_json.keys + assert_equal %w[results hits errors], response_json.keys assert_instance_of Array, response_json['results'] - assert_instance_of Integer, response_json['pagination']['hits'] + assert_instance_of Integer, response_json['hits'] end end @@ -1281,9 +1281,9 @@ def source_filter_count(controller) assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type response_json = JSON.parse(response.body) - assert_equal %w[results pagination errors], response_json.keys + assert_equal %w[results hits errors], response_json.keys assert_instance_of Array, response_json['results'] - assert_instance_of Integer, response_json['pagination']['hits'] + assert_instance_of Integer, response_json['hits'] end end @@ -1296,9 +1296,9 @@ def source_filter_count(controller) assert_response :success assert_equal 'application/json; charset=utf-8', response.content_type response_json = JSON.parse(response.body) - assert_equal %w[results pagination errors], response_json.keys + assert_equal %w[results hits errors], response_json.keys assert_instance_of Array, response_json['results'] - assert_instance_of Integer, response_json['pagination']['hits'] + assert_instance_of Integer, response_json['hits'] end end From a58637bc6a030f0f6bfe8a4638d2db320db199a3 Mon Sep 17 00:00:00 2001 From: Matthew Bernhardt Date: Fri, 28 Aug 2026 15:59:57 -0400 Subject: [PATCH 5/5] Code review feedback --- test/controllers/search_controller_test.rb | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/controllers/search_controller_test.rb b/test/controllers/search_controller_test.rb index eff066b4..95b19c82 100644 --- a/test/controllers/search_controller_test.rb +++ b/test/controllers/search_controller_test.rb @@ -1271,6 +1271,30 @@ def source_filter_count(controller) end end + test 'results in JSON format will report zero hit count in the face of missing data' do + SearchController.any_instance.stubs(:load_timdex_results).returns(nil) + secret_value = 'sooper_sekret' + quepid_ua = 'Quepid/1.0 (Web Scraper)' + # Test @pagination pathway + ClimateControl.modify FORMAT_TOKEN: secret_value do + get "/results?q=test&tab=timdex&format=json&format_token=#{secret_value}", + headers: { 'HTTP_USER_AGENT' => quepid_ua } + assert_response :success + response_json = JSON.parse(response.body) + assert_equal %w[results hits errors], response_json.keys + assert_equal 0, response_json['hits'] + end + # Test @load_more pathway + ClimateControl.modify(FORMAT_TOKEN: secret_value, FEATURE_PAGINATION_LOAD_MORE: 'true') do + get "/results?q=test&tab=timdex&format=json&format_token=#{secret_value}", + headers: { 'HTTP_USER_AGENT' => quepid_ua } + assert_response :success + response_json = JSON.parse(response.body) + assert_equal %w[results hits errors], response_json.keys + assert_equal 0, response_json['hits'] + end + end + test 'results can be returned in JSON format when env is set and valid token is provided even with bot challenge' do secret_value = 'sooper_sekret' quepid_ua = 'Quepid/1.0 (Web Scraper)'