Skip to content

Commit 2b006af

Browse files
justin808claude
andcommitted
Add integration test for body duplication prevention
Addresses test coverage gap identified in code review. The new test: 1. Simulates a mid-stream connection error after partial chunks are sent 2. Verifies that StreamRequest properly retries with a fresh request 3. Confirms no duplicate chunks are yielded to the client Test scenario: - First attempt: sends "Chunk 1" then raises HTTPX::HTTPError - Second attempt: successfully sends all 3 chunks - Expected result: client receives exactly ["Chunk 1", "Chunk 2", "Chunk 3"] - If HTTPx retries were enabled: would receive 4 chunks (duplication!) This integration test validates the complete fix for #1895 by ensuring that the combination of connection_without_retries and StreamRequest's retry logic prevents body duplication. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent bae4005 commit 2b006af

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

react_on_rails_pro/spec/react_on_rails_pro/request_spec.rb

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,6 @@
204204
# Reset connections to ensure we're using a fresh connection
205205
described_class.reset_connection
206206

207-
# Create a spy to check if retries plugin is used
208-
allow(HTTPX).to receive(:plugin).and_call_original
209-
210207
# Trigger a streaming request
211208
mock_streaming_response(render_full_url, 200) do |yielder|
212209
yielder.call("Test chunk\n")
@@ -224,5 +221,56 @@
224221
connection_without_retries = described_class.send(:connection_without_retries)
225222
expect(connection_without_retries).to be_a(HTTPX::Session)
226223
end
224+
225+
it "prevents body duplication when streaming request is retried after mid-transmission error" do
226+
# This integration test verifies the complete fix for https://github.com/shakacode/react_on_rails/issues/1895
227+
# It ensures that when a streaming request fails mid-transmission and is retried,
228+
# the client doesn't receive duplicate chunks.
229+
230+
described_class.reset_connection
231+
232+
# Track how many times the request is made to verify retry behavior
233+
request_attempt = 0
234+
original_chunks = ["Chunk 1", "Chunk 2", "Chunk 3"]
235+
236+
# Mock a streaming response that fails on first attempt, succeeds on second
237+
connection = described_class.send(:connection_without_retries)
238+
allow(connection).to receive(:post).and_wrap_original do |original_method, *args, **kwargs|
239+
if kwargs[:stream]
240+
request_attempt += 1
241+
242+
# Set up mock based on attempt number
243+
if request_attempt == 1
244+
# First attempt: simulate mid-transmission failure (HTTPError during streaming)
245+
# This simulates a connection error after partial data is sent
246+
mock_streaming_response(render_full_url, 200) do |yielder|
247+
yielder.call("#{original_chunks[0]}\n")
248+
# Simulate connection error mid-stream
249+
raise HTTPX::HTTPError.new("Connection error", nil)
250+
end
251+
else
252+
# Second attempt: complete all chunks successfully
253+
mock_streaming_response(render_full_url, 200) do |yielder|
254+
original_chunks.each { |chunk| yielder.call("#{chunk}\n") }
255+
end
256+
end
257+
end
258+
259+
original_method.call(*args, **kwargs)
260+
end
261+
262+
stream = described_class.render_code_as_stream("/render", "console.log('test');", is_rsc_payload: false)
263+
received_chunks = []
264+
265+
# StreamRequest should handle the retry and yield all chunks exactly once
266+
stream.each_chunk { |chunk| received_chunks << chunk }
267+
268+
# Verify no duplication: should have exactly 3 chunks, not 4 (1 from failed + 3 from retry)
269+
expect(received_chunks).to eq(original_chunks)
270+
expect(received_chunks.size).to eq(3)
271+
272+
# Verify retry actually happened
273+
expect(request_attempt).to eq(2)
274+
end
227275
end
228276
end

0 commit comments

Comments
 (0)