'use strict';
import {
insertNodesAndExecuteScripts,
getVisibleChildren,
} from '../test-utils/FizzTestUtils';
import {patchMessageChannel} from '../../../../scripts/jest/patchMessageChannel';
global.ReadableStream =
require('web-streams-polyfill/ponyfill/es6').ReadableStream;
global.TextEncoder = require('util').TextEncoder;
let act;
let serverAct;
let assertLog;
let waitForPaint;
let container;
let React;
let Scheduler;
let ReactDOMServer;
let ReactDOMClient;
let useDeferredValue;
let Suspense;
describe('ReactDOMFizzForm', () => {
beforeEach(() => {
jest.resetModules();
Scheduler = require('scheduler');
patchMessageChannel();
act = require('internal-test-utils').act;
serverAct = require('internal-test-utils').serverAct;
React = require('react');
ReactDOMServer = require('react-dom/server.browser');
ReactDOMClient = require('react-dom/client');
useDeferredValue = React.useDeferredValue;
Suspense = React.Suspense;
assertLog = require('internal-test-utils').assertLog;
waitForPaint = require('internal-test-utils').waitForPaint;
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
});
async function readIntoContainer(stream) {
const reader = stream.getReader();
let result = '';
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
result += Buffer.from(value).toString('utf8');
}
const temp = document.createElement('div');
temp.innerHTML = result;
insertNodesAndExecuteScripts(temp, container, null);
}
function Text({text}) {
Scheduler.log(text);
return text;
}
it('returns initialValue argument, if provided', async () => {
function App() {
return useDeferredValue('Final', 'Initial');
}
const stream = await serverAct(() =>
ReactDOMServer.renderToReadableStream(<App />),
);
await readIntoContainer(stream);
expect(container.textContent).toEqual('Initial');
await act(() => ReactDOMClient.hydrateRoot(container, <App />));
expect(container.textContent).toEqual('Final');
});
it(
'if initial value postpones during hydration, it will switch to the ' +
'final value instead',
async () => {
function Content() {
const isInitial = useDeferredValue(false, true);
if (isInitial) {
React.unstable_postpone();
}
return <Text text="Final" />;
}
function App() {
return (
<div>
<Suspense fallback={<Text text="Loading..." />}>
<Content />
</Suspense>
</div>
);
}
const stream = await serverAct(() =>
ReactDOMServer.renderToReadableStream(<App />),
);
await readIntoContainer(stream);
expect(container.textContent).toEqual('Loading...');
assertLog(['Loading...']);
await act(() => ReactDOMClient.hydrateRoot(container, <App />));
expect(container.textContent).toEqual('Final');
assertLog(['Loading...', 'Final']);
},
);
it(
'useDeferredValue during hydration has higher priority than remaining ' +
'incremental hydration',
async () => {
function B() {
const text = useDeferredValue('B [Final]', 'B [Initial]');
return <Text text={text} />;
}
function App() {
return (
<div>
<span>
<Text text="A" />
</span>
<Suspense fallback={<Text text="Loading..." />}>
<span>
<B />
</span>
<div>
<Suspense fallback={<Text text="Loading..." />}>
<span id="C" ref={cRef}>
<Text text="C" />
</span>
</Suspense>
</div>
</Suspense>
</div>
);
}
const cRef = React.createRef();
const stream = await serverAct(() =>
ReactDOMServer.renderToReadableStream(<App />),
);
await readIntoContainer(stream);
assertLog(['A', 'B [Initial]', 'C']);
expect(getVisibleChildren(container)).toEqual(
<div>
<span>A</span>
<span>B [Initial]</span>
<div>
<span id="C">C</span>
</div>
</div>,
);
const serverRenderedC = document.getElementById('C');
await act(async () => {
ReactDOMClient.hydrateRoot(container, <App />);
await waitForPaint(['A']);
expect(cRef.current).toBe(null);
await waitForPaint(['B [Initial]']);
expect(getVisibleChildren(container)).toEqual(
<div>
<span>A</span>
<span>B [Initial]</span>
<div>
<span id="C">C</span>
</div>
</div>,
);
expect(cRef.current).toBe(null);
await waitForPaint(['B [Final]']);
expect(getVisibleChildren(container)).toEqual(
<div>
<span>A</span>
<span>B [Final]</span>
<div>
<span id="C">C</span>
</div>
</div>,
);
expect(cRef.current).toBe(null);
});
assertLog(['C']);
expect(getVisibleChildren(container)).toEqual(
<div>
<span>A</span>
<span>B [Final]</span>
<div>
<span id="C">C</span>
</div>
</div>,
);
expect(cRef.current).toBe(serverRenderedC);
},
);
});