Skip to content

Commit

Permalink
have abort path run through onError
Browse files Browse the repository at this point in the history
  • Loading branch information
gnoff committed May 30, 2022
1 parent 5eedbfd commit 110a01f
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 8 deletions.
12 changes: 10 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Expand Up @@ -1047,9 +1047,15 @@ describe('ReactDOMFizzServer', () => {
);
}

const loggedErrors = [];
function onError(error) {
loggedErrors.push(error);
return `Hash of (${error.message})`;
}

let controls;
await act(async () => {
controls = ReactDOMFizzServer.renderToPipeableStream(<App />);
controls = ReactDOMFizzServer.renderToPipeableStream(<App />, {onError});
controls.pipe(writable);
});

Expand Down Expand Up @@ -1077,7 +1083,9 @@ describe('ReactDOMFizzServer', () => {
expectErrors(
errors,
['This Suspense boundary was aborted by the server'],
['This Suspense boundary was aborted by the server'],
[
'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
],
);
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);

Expand Down
Expand Up @@ -193,20 +193,30 @@ describe('ReactDOMFizzServer', () => {

// @gate experimental
it('should be able to complete by aborting even if the promise never resolves', async () => {
const errors = [];
const controller = new AbortController();
const stream = await ReactDOMFizzServer.renderToReadableStream(
<div>
<Suspense fallback={<div>Loading</div>}>
<InfiniteSuspend />
</Suspense>
</div>,
{signal: controller.signal},
{
signal: controller.signal,
onError(x) {
errors.push(x.message);
},
},
);

controller.abort();

const result = await readResult(stream);
expect(result).toContain('Loading');

expect(errors).toEqual([
'This Suspense boundary was aborted by the server',
]);
});

// @gate experimental
Expand All @@ -223,12 +233,18 @@ describe('ReactDOMFizzServer', () => {
rendered = true;
return 'Done';
}
const errors = [];
const stream = await ReactDOMFizzServer.renderToReadableStream(
<div>
<Suspense fallback={<div>Loading</div>}>
<Wait /> />
</Suspense>
</div>,
{
onError(x) {
errors.push(x.message);
},
},
);

stream.allReady.then(() => (isComplete = true));
Expand All @@ -239,6 +255,10 @@ describe('ReactDOMFizzServer', () => {
const reader = stream.getReader();
reader.cancel();

expect(errors).toEqual([
'This Suspense boundary was aborted by the server',
]);

hasLoaded = true;
resolve();

Expand Down
30 changes: 28 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
Expand Up @@ -211,7 +211,7 @@ describe('ReactDOMFizzServer', () => {

{
onError(x) {
reportedErrors.push(x);
reportedErrors.push(x.message);
},
onShellError(x) {
reportedShellErrors.push(x);
Expand All @@ -224,7 +224,10 @@ describe('ReactDOMFizzServer', () => {

expect(output.error).toBe(theError);
expect(output.result).toBe('');
expect(reportedErrors).toEqual([theError]);
expect(reportedErrors).toEqual([
theError.message,
'This Suspense boundary was aborted by the server',
]);
expect(reportedShellErrors).toEqual([theError]);
});

Expand Down Expand Up @@ -289,6 +292,7 @@ describe('ReactDOMFizzServer', () => {
// @gate experimental
it('should be able to complete by aborting even if the promise never resolves', async () => {
let isCompleteCalls = 0;
const errors = [];
const {writable, output, completed} = getTestWritable();
const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
<div>
Expand All @@ -298,6 +302,9 @@ describe('ReactDOMFizzServer', () => {
</div>,

{
onError(x) {
errors.push(x.message);
},
onAllReady() {
isCompleteCalls++;
},
Expand All @@ -314,6 +321,9 @@ describe('ReactDOMFizzServer', () => {

await completed;

expect(errors).toEqual([
'This Suspense boundary was aborted by the server',
]);
expect(output.error).toBe(undefined);
expect(output.result).toContain('Loading');
expect(isCompleteCalls).toBe(1);
Expand All @@ -322,6 +332,7 @@ describe('ReactDOMFizzServer', () => {
// @gate experimental
it('should be able to complete by abort when the fallback is also suspended', async () => {
let isCompleteCalls = 0;
const errors = [];
const {writable, output, completed} = getTestWritable();
const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
<div>
Expand All @@ -333,6 +344,9 @@ describe('ReactDOMFizzServer', () => {
</div>,

{
onError(x) {
errors.push(x.message);
},
onAllReady() {
isCompleteCalls++;
},
Expand All @@ -349,6 +363,11 @@ describe('ReactDOMFizzServer', () => {

await completed;

expect(errors).toEqual([
// There are two boundaries that abort
'This Suspense boundary was aborted by the server',
'This Suspense boundary was aborted by the server',
]);
expect(output.error).toBe(undefined);
expect(output.result).toContain('Loading');
expect(isCompleteCalls).toBe(1);
Expand Down Expand Up @@ -552,6 +571,7 @@ describe('ReactDOMFizzServer', () => {
rendered = true;
return 'Done';
}
const errors = [];
const {writable, completed} = getTestWritable();
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
<div>
Expand All @@ -560,6 +580,9 @@ describe('ReactDOMFizzServer', () => {
</Suspense>
</div>,
{
onError(x) {
errors.push(x.message);
},
onAllReady() {
isComplete = true;
},
Expand All @@ -579,6 +602,9 @@ describe('ReactDOMFizzServer', () => {

await completed;

expect(errors).toEqual([
'This Suspense boundary was aborted by the server',
]);
expect(rendered).toBe(false);
expect(isComplete).toBe(true);
});
Expand Down
Expand Up @@ -171,6 +171,7 @@ describe('ReactDOMServerFB', () => {
});

it('should be able to complete by aborting even if the promise never resolves', () => {
const errors = [];
const stream = ReactDOMServer.renderToStream(
<div>
<Suspense fallback={<div>Loading</div>}>
Expand All @@ -179,7 +180,7 @@ describe('ReactDOMServerFB', () => {
</div>,
{
onError(x) {
console.error(x);
errors.push(x.message);
},
},
);
Expand All @@ -191,5 +192,9 @@ describe('ReactDOMServerFB', () => {

const remaining = readResult(stream);
expect(remaining).toEqual('');

expect(errors).toEqual([
'This Suspense boundary was aborted by the server',
]);
});
});
9 changes: 7 additions & 2 deletions packages/react-server/src/ReactFizzServer.js
Expand Up @@ -1499,8 +1499,13 @@ function abortTask(task: Task): void {

if (!boundary.forceClientRender) {
boundary.forceClientRender = true;
boundary.errorMessage =
'This Suspense boundary was aborted by the server';
const error = new Error(
'This Suspense boundary was aborted by the server',
);
boundary.errorHash = request.onError(error);
if (__DEV__) {
captureBoundaryErrorDetailsDev(boundary, error);
}
if (boundary.parentFlushed) {
request.clientRenderedBoundaries.push(boundary);
}
Expand Down

0 comments on commit 110a01f

Please sign in to comment.