11# frozen_string_literal: true
22
3+ require "async"
4+ require "async/queue"
35require "rails_helper"
46require "support/script_tag_utils"
57
@@ -327,6 +329,7 @@ def response; end
327329 HTML
328330 end
329331
332+ # Mock chunks can be Async::Queue or Array
330333 def mock_request_and_response ( mock_chunks = chunks , count : 1 )
331334 # Reset connection instance variables to ensure clean state for tests
332335 ReactOnRailsPro ::Request . instance_variable_set ( :@connection , nil )
@@ -339,9 +342,16 @@ def mock_request_and_response(mock_chunks = chunks, count: 1)
339342 chunks_read . clear
340343 mock_streaming_response ( %r{http://localhost:3800/bundles/[a-f0-9]{32}-test/render/[a-f0-9]{32}} , 200 ,
341344 count : count ) do |yielder |
342- mock_chunks . each do |chunk |
343- chunks_read << chunk
344- yielder . call ( "#{ chunk . to_json } \n " )
345+ if mock_chunks . is_a? ( Async ::Queue )
346+ while ( chunk = mock_chunks . dequeue )
347+ chunks_read << chunk
348+ yielder . call ( "#{ chunk . to_json } \n " )
349+ end
350+ else
351+ mock_chunks . each do |chunk |
352+ chunks_read << chunk
353+ yielder . call ( "#{ chunk . to_json } \n " )
354+ end
345355 end
346356 end
347357 end
@@ -411,6 +421,7 @@ def mock_request_and_response(mock_chunks = chunks, count: 1)
411421 describe "stream_view_containing_react_components" do # rubocop:disable RSpec/MultipleMemoizedHelpers
412422 let ( :mocked_stream ) { instance_double ( ActionController ::Live ::Buffer ) }
413423 let ( :written_chunks ) { [ ] }
424+ let ( :chunks_queue ) { Async ::Queue . new }
414425
415426 before do
416427 written_chunks . clear
@@ -428,18 +439,55 @@ def mock_request_and_response(mock_chunks = chunks, count: 1)
428439
429440 allow ( mocked_stream ) . to receive ( :write ) do |chunk |
430441 written_chunks << chunk
431- # Ensures that any chunk received is written immediately to the stream
432- expect ( written_chunks . count ) . to eq ( chunks_read . count ) # rubocop:disable RSpec/ExpectInHook
433442 end
434443 allow ( mocked_stream ) . to receive ( :close )
435444 mocked_response = instance_double ( ActionDispatch ::Response )
436445 allow ( mocked_response ) . to receive ( :stream ) . and_return ( mocked_stream )
437446 allow ( self ) . to receive ( :response ) . and_return ( mocked_response )
438- mock_request_and_response
447+ mock_request_and_response ( chunks_queue )
448+ end
449+
450+ def run_stream
451+ queue = chunks_queue
452+ Sync do |parent |
453+ parent . async do
454+ stream_view_containing_react_components ( template : template_path )
455+ end
456+
457+ writer = Object . new
458+ chunks_to_write = chunks . dup
459+ writer . define_singleton_method ( :write_next_chunk ) do
460+ chunk = chunks_to_write . shift
461+ if chunk . nil?
462+ queue . close
463+ parent . sleep 0.05
464+ return nil
465+ end
466+
467+ queue . enqueue ( chunk )
468+ parent . sleep 0.05
469+ chunk
470+ end
471+ writer . define_singleton_method ( :write_rest_of_chunks ) do
472+ while ( chunk = chunks_to_write . shift )
473+ queue . enqueue ( chunk )
474+ end
475+ parent . sleep 0.1
476+ end
477+ yield ( writer )
478+ end
439479 end
440480
441481 it "writes the chunk to stream as soon as it is received" do
442- stream_view_containing_react_components ( template : template_path )
482+ run_stream do |writer |
483+ expect ( self ) . to have_received ( :render_to_string )
484+
485+ while writer . write_next_chunk
486+ # Ensures that any chunk received is written immediately to the stream
487+ expect ( written_chunks . count ) . to eq ( chunks_read . count )
488+ end
489+ end
490+
443491 expect ( self ) . to have_received ( :render_to_string ) . once . with ( template : template_path )
444492 expect ( chunks_read . count ) . to eq ( chunks . count )
445493 expect ( written_chunks . count ) . to eq ( chunks . count )
0 commit comments