@@ -2,70 +2,80 @@ import { Readable, PassThrough } from 'stream';
22import ReactOnRails , { RailsContext } from '../src/ReactOnRails.node.ts' ;
33import injectRSCPayload from '../src/injectRSCPayload.ts' ;
44
5- describe ( 'injectRSCPayload' , ( ) => {
6- const createMockStream = ( chunks : ( string | Buffer ) [ ] | { [ key : number ] : string | string [ ] } ) => {
7- if ( Array . isArray ( chunks ) ) {
8- return Readable . from (
9- chunks . map ( ( chunk ) => ( typeof chunk === 'string' ? new TextEncoder ( ) . encode ( chunk ) : chunk ) ) ,
10- ) ;
11- }
12- const passThrough = new PassThrough ( ) ;
13- const entries = Object . entries ( chunks ) ;
14- const keysLength = entries . length ;
15- entries . forEach ( ( [ delay , value ] , index ) => {
16- setTimeout ( ( ) => {
17- const chunksArray = Array . isArray ( value ) ? value : [ value ] ;
18- chunksArray . forEach ( ( chunk ) => {
19- passThrough . push ( new TextEncoder ( ) . encode ( chunk ) ) ;
20- } ) ;
21- if ( index === keysLength - 1 ) {
22- passThrough . push ( null ) ;
23- }
24- } , + delay ) ;
25- } ) ;
26- return passThrough ;
27- } ;
5+ // Shared utilities
6+ const createMockStream = ( chunks : ( string | Buffer ) [ ] | { [ key : number ] : string | string [ ] } ) => {
7+ if ( Array . isArray ( chunks ) ) {
8+ return Readable . from (
9+ chunks . map ( ( chunk ) => ( typeof chunk === 'string' ? new TextEncoder ( ) . encode ( chunk ) : chunk ) ) ,
10+ ) ;
11+ }
12+ const passThrough = new PassThrough ( ) ;
13+ const entries = Object . entries ( chunks ) ;
14+ const keysLength = entries . length ;
15+ entries . forEach ( ( [ delay , value ] , index ) => {
16+ setTimeout ( ( ) => {
17+ const chunksArray = Array . isArray ( value ) ? value : [ value ] ;
18+ chunksArray . forEach ( ( chunk ) => {
19+ passThrough . push ( new TextEncoder ( ) . encode ( chunk ) ) ;
20+ } ) ;
21+ if ( index === keysLength - 1 ) {
22+ passThrough . push ( null ) ;
23+ }
24+ } , + delay ) ;
25+ } ) ;
26+ return passThrough ;
27+ } ;
28+
29+ const collectStreamData = async ( stream : Readable ) => {
30+ const chunks : string [ ] = [ ] ;
31+ for await ( const chunk of stream ) {
32+ chunks . push ( new TextDecoder ( ) . decode ( chunk as Buffer ) ) ;
33+ }
34+ return chunks . join ( '' ) ;
35+ } ;
36+
37+ // Test setup helper
38+ const setupTest = ( mockRSC : Readable ) => {
39+ jest . spyOn ( ReactOnRails , 'onRSCPayloadGenerated' ) . mockImplementation ( ( _railsContext , callback ) => {
40+ callback ( { stream : mockRSC , componentName : 'test' , props : { } } ) ;
41+ } ) ;
2842
29- const collectStreamData = async ( stream : Readable ) => {
30- const chunks : string [ ] = [ ] ;
31- for await ( const chunk of stream ) {
32- chunks . push ( new TextDecoder ( ) . decode ( chunk as Buffer ) ) ;
33- }
34- return chunks . join ( '' ) ;
35- } ;
43+ const railsContext = {
44+ componentSpecificMetadata : {
45+ renderRequestId : '123' ,
46+ } ,
47+ } as RailsContext ;
3648
49+ return { railsContext } ;
50+ } ;
51+
52+ describe ( 'injectRSCPayload' , ( ) => {
3753 it ( 'should inject RSC payload as script tags' , async ( ) => {
3854 const mockRSC = createMockStream ( [ '{"test": "data"}' ] ) ;
3955 const mockHTML = createMockStream ( [ '<html><body><div>Hello, world!</div></body></html>' ] ) ;
56+ const { railsContext } = setupTest ( mockRSC ) ;
4057
41- jest
42- . spyOn ( ReactOnRails , 'getRSCPayloadStreams' )
43- . mockReturnValue ( [ { stream : mockRSC , componentName : 'test' , props : { } } ] ) ;
44-
45- const result = injectRSCPayload ( mockHTML , { } as RailsContext ) ;
58+ const result = injectRSCPayload ( mockHTML , railsContext ) ;
4659 const resultStr = await collectStreamData ( result ) ;
4760
4861 expect ( resultStr ) . toContain (
49- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data\\"}")</script>' ,
62+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data\\"}")</script>` ,
5063 ) ;
5164 } ) ;
5265
5366 it ( 'should handle multiple RSC payloads' , async ( ) => {
5467 const mockRSC = createMockStream ( [ '{"test": "data"}' , '{"test": "data2"}' ] ) ;
5568 const mockHTML = createMockStream ( [ '<html><body><div>Hello, world!</div></body></html>' ] ) ;
69+ const { railsContext } = setupTest ( mockRSC ) ;
5670
57- jest
58- . spyOn ( ReactOnRails , 'getRSCPayloadStreams' )
59- . mockReturnValue ( [ { stream : mockRSC , componentName : 'test' , props : { } } ] ) ;
60-
61- const result = injectRSCPayload ( mockHTML , { } as RailsContext ) ;
71+ const result = injectRSCPayload ( mockHTML , railsContext ) ;
6272 const resultStr = await collectStreamData ( result ) ;
6373
6474 expect ( resultStr ) . toContain (
65- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data\\"}")</script>' ,
75+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data\\"}")</script>` ,
6676 ) ;
6777 expect ( resultStr ) . toContain (
68- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data2\\"}")</script>' ,
78+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data2\\"}")</script>` ,
6979 ) ;
7080 } ) ;
7181
@@ -75,18 +85,16 @@ describe('injectRSCPayload', () => {
7585 '<html><body><div>Hello, world!</div></body></html>' ,
7686 '<div>Next chunk</div>' ,
7787 ] ) ;
78- jest
79- . spyOn ( ReactOnRails , 'getRSCPayloadStreams' )
80- . mockReturnValue ( [ { stream : mockRSC , componentName : 'test' , props : { } } ] ) ;
88+ const { railsContext } = setupTest ( mockRSC ) ;
8189
82- const result = injectRSCPayload ( mockHTML , { } as RailsContext ) ;
90+ const result = injectRSCPayload ( mockHTML , railsContext ) ;
8391 const resultStr = await collectStreamData ( result ) ;
8492
8593 expect ( resultStr ) . toEqual (
8694 '<html><body><div>Hello, world!</div></body></html>' +
8795 '<div>Next chunk</div>' +
88- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data\\"}")</script>' +
89- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data2\\"}")</script>' ,
96+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data\\"}")</script>` +
97+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data2\\"}")</script>` ,
9098 ) ;
9199 } ) ;
92100
@@ -96,17 +104,15 @@ describe('injectRSCPayload', () => {
96104 0 : '<html><body><div>Hello, world!</div></body></html>' ,
97105 100 : '<div>Next chunk</div>' ,
98106 } ) ;
99- jest
100- . spyOn ( ReactOnRails , 'getRSCPayloadStreams' )
101- . mockReturnValue ( [ { stream : mockRSC , componentName : 'test' , props : { } } ] ) ;
107+ const { railsContext } = setupTest ( mockRSC ) ;
102108
103- const result = injectRSCPayload ( mockHTML , { } as RailsContext ) ;
109+ const result = injectRSCPayload ( mockHTML , railsContext ) ;
104110 const resultStr = await collectStreamData ( result ) ;
105111
106112 expect ( resultStr ) . toEqual (
107113 '<html><body><div>Hello, world!</div></body></html>' +
108- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data\\"}")</script>' +
109- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data2\\"}")</script>' +
114+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data\\"}")</script>` +
115+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data2\\"}")</script>` +
110116 '<div>Next chunk</div>' ,
111117 ) ;
112118 } ) ;
@@ -120,18 +126,16 @@ describe('injectRSCPayload', () => {
120126 100 : [ '<html><body><div>Hello, world!</div></body></html>' , '<div>Next chunk</div>' ] ,
121127 200 : '<div>Third chunk</div>' ,
122128 } ) ;
123- jest
124- . spyOn ( ReactOnRails , 'getRSCPayloadStreams' )
125- . mockReturnValue ( [ { stream : mockRSC , componentName : 'test' , props : { } } ] ) ;
129+ const { railsContext } = setupTest ( mockRSC ) ;
126130
127- const result = injectRSCPayload ( mockHTML , { } as RailsContext ) ;
131+ const result = injectRSCPayload ( mockHTML , railsContext ) ;
128132 const resultStr = await collectStreamData ( result ) ;
129133
130134 expect ( resultStr ) . toEqual (
131135 '<html><body><div>Hello, world!</div></body></html>' +
132136 '<div>Next chunk</div>' +
133- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data\\"}")</script>' +
134- ' <script>(self.REACT_ON_RAILS_RSC_PAYLOAD ||=[] ).push("{\\"test\\": \\"data2\\"}")</script>' +
137+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data\\"}")</script>` +
138+ ` <script>(( self.REACT_ON_RAILS_RSC_PAYLOADS ||={})["test-{}-123"]||=[] ).push("{\\"test\\": \\"data2\\"}")</script>` +
135139 '<div>Third chunk</div>' ,
136140 ) ;
137141 } ) ;
0 commit comments