diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 22d2279578ff0..8442fa3c1316d 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -94,9 +94,7 @@ describe('ReactDOMFizzServer', () => { ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); ReactDOMFizzServer = require('react-dom/server'); - if (__EXPERIMENTAL__) { - ReactDOMFizzStatic = require('react-dom/static'); - } + ReactDOMFizzStatic = require('react-dom/static'); Stream = require('stream'); Suspense = React.Suspense; use = React.use; @@ -10784,4 +10782,54 @@ Unfortunately that previous paragraph wasn't quite long enough so I'll continue // Instead we assert that we never emitted the fallback of the Suspense boundary around the body. expect(streamedContent).not.toContain(randomTag); }); + + it('should be able to Suspend after aborting in the same component without hanging the render', async () => { + const controller = new AbortController(); + + const promise1 = new Promise(() => {}); + function AbortAndSuspend() { + controller.abort('boom'); + return React.use(promise1); + } + + function App() { + return ( + + + + {/* + The particular code path that was problematic required the Suspend to happen in renderNode + rather than retryRenderTask so we render the aborting function inside a host component + intentionally here + */} +
+ +
+
+ + + ); + } + + const errors = []; + await act(async () => { + const result = await ReactDOMFizzStatic.prerenderToNodeStream(, { + signal: controller.signal, + onError(e) { + errors.push(e); + }, + }); + + result.prelude.pipe(writable); + }); + + expect(errors).toEqual(['boom']); + + expect(getVisibleChildren(document)).toEqual( + + + loading... + , + ); + }); }); diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index d619385ec7db3..8681d03b22907 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -4155,7 +4155,9 @@ function renderNode( getSuspendedThenable() : thrownValue; - if (typeof x === 'object' && x !== null) { + if (request.status === ABORTING) { + // We are aborting so we can just bubble up to the task by falling through + } else if (typeof x === 'object' && x !== null) { // $FlowFixMe[method-unbinding] if (typeof x.then === 'function') { const wakeable: Wakeable = (x: any); @@ -4254,7 +4256,9 @@ function renderNode( getSuspendedThenable() : thrownValue; - if (typeof x === 'object' && x !== null) { + if (request.status === ABORTING) { + // We are aborting so we can just bubble up to the task by falling through + } else if (typeof x === 'object' && x !== null) { // $FlowFixMe[method-unbinding] if (typeof x.then === 'function') { const wakeable: Wakeable = (x: any);