diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 995f0da37ec..940e6c3374f 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -321,6 +321,74 @@ describe('ReactFlightDOMEdge', () => { expect(result).toEqual('Client Component'); }); + it('should resolve cyclic references in client component props after two rounds of serialization and deserialization', async () => { + const ClientComponent = clientExports(function ClientComponent({data}) { + return ( +
{data.self === data ? 'Cycle resolved' : 'Cycle broken'}
+ ); + }); + const clientModuleMetadata = webpackMap[ClientComponent.$$id]; + const consumerModuleId = 'consumer-' + clientModuleMetadata.id; + const clientReference = Object.defineProperties(ClientComponent, { + $$typeof: {value: Symbol.for('react.client.reference')}, + $$id: {value: ClientComponent.$$id}, + }); + webpackModules[consumerModuleId] = clientReference; + + const cyclic = {self: null}; + cyclic.self = cyclic; + + const stream1 = ReactServerDOMServer.renderToReadableStream( + + + , + webpackMap, + ); + + const promise = ReactServerDOMClient.createFromReadableStream(stream1, { + serverConsumerManifest: { + moduleMap: { + [clientModuleMetadata.id]: { + '*': { + id: consumerModuleId, + chunks: [], + name: '*', + }, + }, + }, + moduleLoading: webpackModuleLoading, + serverModuleMap: null, + }, + }); + + const errors = []; + const stream2 = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(promise, webpackMap, { + onError(error) { + errors.push(error); + }, + }), + ); + + expect(errors).toEqual([]); + + const element = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream2, { + serverConsumerManifest: { + moduleMap: null, + moduleLoading: null, + }, + }), + ); + + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(element), + ); + const result = await readResult(ssrStream); + + expect(result).toBe('
Cycle resolved
'); + }); + it('should be able to load a server reference on a consuming server if a mapping exists', async () => { function greet(name) { return 'hi, ' + name; diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 021913636bd..1f9bb0a77fa 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -3622,8 +3622,8 @@ function renderModelDestructive( return renderModelDestructive( request, task, - emptyRoot, - '', + parent, + parentPropertyName, resolvedModel, ); }