/*** Copyright (c) Meta Platforms, Inc. and affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.** @emails react-core*/'use strict';
let React;
let ReactDOMServer;
let Suspense;
describe('ReactDOMServerFB', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOMServer = require('../ReactDOMServerFB');
Suspense = React.Suspense;
});const theError = new Error('This is an error');
function Throw() {
throw theError;
}const theInfinitePromise = new Promise(() => {});
function InfiniteSuspend() {
throw theInfinitePromise;
}function readResult(stream) {
let result = '';
while (!ReactDOMServer.hasFinished(stream)) {
result += ReactDOMServer.renderNextChunk(stream);
}return result;
}it('should be able to render basic HTML', async () => {
const stream = ReactDOMServer.renderToStream(<div>hello world</div>, {
onError(x) {console.error(x);
},});const result = readResult(stream);expect(result).toMatchInlineSnapshot(`"<div>hello world</div>"`);
});it('should emit bootstrap script src at the end', () => {const stream = ReactDOMServer.renderToStream(<div>hello world</div>, {
bootstrapScriptContent: 'INIT();',bootstrapScripts: ['init.js'],
bootstrapModules: ['init.mjs'],
onError(x) {console.error(x);
},});const result = readResult(stream);expect(result).toMatchInlineSnapshot(
`"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script>INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
);});it('emits all HTML as one unit if we wait until the end to start', async () => {let hasLoaded = false;let resolve;const promise = new Promise(r => (resolve = r));function Wait() {if (!hasLoaded) {throw promise;}return 'Done';}const stream = ReactDOMServer.renderToStream(
<div><Suspense fallback="Loading"><Wait /></Suspense></div>,{onError(x) {console.error(x);
},},);await jest.runAllTimers();
// Resolve the loading.
hasLoaded = true;await resolve();await jest.runAllTimers();
const result = readResult(stream);expect(result).toMatchInlineSnapshot(`"<div><!--$-->Done<!--/$--></div>"`);
});it('should throw an error when an error is thrown at the root', () => {const reportedErrors = [];
const stream = ReactDOMServer.renderToStream(
<div><Throw /></div>,{onError(x) {reportedErrors.push(x);
},},);let caughtError = null;let result = '';try {result = readResult(stream);} catch (x) {caughtError = x;}expect(caughtError).toBe(theError);
expect(result).toBe('');
expect(reportedErrors).toEqual([theError]);
});it('should throw an error when an error is thrown inside a fallback', () => {const reportedErrors = [];
const stream = ReactDOMServer.renderToStream(
<div><Suspense fallback={<Throw />}><InfiniteSuspend /></Suspense></div>,{onError(x) {reportedErrors.push(x);
},},);let caughtError = null;let result = '';try {result = readResult(stream);} catch (x) {caughtError = x;}expect(caughtError).toBe(theError);
expect(result).toBe('');
expect(reportedErrors).toEqual([theError]);
});it('should not throw an error when an error is thrown inside suspense boundary', async () => {const reportedErrors = [];
const stream = ReactDOMServer.renderToStream(
<div><Suspense fallback={<div>Loading</div>}><Throw /></Suspense></div>,{onError(x) {reportedErrors.push(x);
},},);const result = readResult(stream);expect(result).toContain('Loading');
expect(reportedErrors).toEqual([theError]);
});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>}><InfiniteSuspend /></Suspense></div>,{onError(x) {errors.push(x.message);
},},);const partial = ReactDOMServer.renderNextChunk(stream);
expect(partial).toContain('Loading');
ReactDOMServer.abortStream(stream);
const remaining = readResult(stream);expect(remaining).toEqual('');
expect(errors).toEqual([
'The render was aborted by the server without a reason.',]);
});it('should allow setting an abort reason', () => {const errors = [];
const stream = ReactDOMServer.renderToStream(
<div><Suspense fallback={<div>Loading</div>}><InfiniteSuspend /></Suspense></div>,{onError(error) {errors.push(error);
},},);ReactDOMServer.abortStream(stream, theError);
expect(errors).toEqual([theError]);
});});