Skip to content

Commit

Permalink
Add generic test and change to directly flush instead of going throug…
Browse files Browse the repository at this point in the history
…h ping
  • Loading branch information
sebmarkbage committed Mar 5, 2023
1 parent fe2ac55 commit 0a7c2bb
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1046,4 +1046,72 @@ describe('ReactFlightDOM', () => {
});
expect(container.innerHTML).toBe('<p>async hello</p>');
});

// @gate enableUseHook
it('should throw on the client if a passed promise eventually rejects', async () => {
const reportedErrors = [];
const theError = new Error('Server throw');

async function getData() {
throw theError;
}

function Component({data}) {
const text = use(data);
return <p>{text}</p>;
}

const ClientComponent = clientExports(Component);

function ServerComponent() {
const data = getData(); // no await here
return <ClientComponent data={data} />;
}

function Await({response}) {
return use(response);
}

function App({response}) {
return (
<Suspense fallback={<h1>Loading...</h1>}>
<ErrorBoundary
fallback={e => (
<p>
{__DEV__ ? e.message + ' + ' : null}
{e.digest}
</p>
)}>
<Await response={response} />
</ErrorBoundary>
</Suspense>
);
}

const {writable, readable} = getTestStream();
const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
<ServerComponent />,
webpackMap,
{
onError(x) {
reportedErrors.push(x);
return __DEV__ ? 'a dev digest' : `digest("${x.message}")`;
},
},
);
pipe(writable);
const response = ReactServerDOMReader.createFromReadableStream(readable);

const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await act(async () => {
root.render(<App response={response} />);
});
expect(container.innerHTML).toBe(
__DEV__
? '<p>Server throw + a dev digest</p>'
: '<p>digest("Server throw")</p>',
);
expect(reportedErrors).toEqual([theError]);
});
});
8 changes: 5 additions & 3 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,18 @@ function serializeThenable(request: Request, thenable: Thenable<any>): number {
pingTask(request, newTask);
},
reason => {
// TODO: Is it safe to directly emit these without being inside a retry?
newTask.status = ERRORED;
// TODO: We should ideally do this inside performWork so it's scheduled
const digest = logRecoverableError(request, reason);
if (__DEV__) {
const {message, stack} = getErrorMessageAndStackDev(reason);
emitErrorChunkDev(request, newTask.id, digest, message, stack);
} else {
emitErrorChunkProd(request, newTask.id, digest);
}
newTask.status = ERRORED;
pingTask(request, newTask);
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
},
);

Expand Down

0 comments on commit 0a7c2bb

Please sign in to comment.