/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-dom/src/__tests__/ReactDOMFizzDeferredValue-test.js
231 строка
6 KB
Sebastian Markbåge
Unify serverAct helpers (#33327)
21 май 2025, 23:13
Не верифицирован
21 май 2025, 23:13
1c43d0a
Код
Авторство
О чём код?
/** * 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'; import { insertNodesAndExecuteScripts, getVisibleChildren, } from '../test-utils/FizzTestUtils'; import {patchMessageChannel} from '../../../../scripts/jest/patchMessageChannel'; // Polyfills for test environment 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'); // After hydration, it's updated to the final value await act(() => ReactDOMClient.hydrateRoot(container, <App />)); expect(container.textContent).toEqual('Final'); }); // @gate enablePostpone 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...']); // After hydration, it's updated to the final value 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'); // On the client, we first hydrate the initial value, then upgrade // to final. await act(async () => { ReactDOMClient.hydrateRoot(container, <App />); // First the outermost Suspense boundary hydrates. await waitForPaint(['A']); expect(cRef.current).toBe(null); // Then the next level hydrates. This level includes a useDeferredValue, // so we should prioritize upgrading it before we proceed to hydrating // additional levels. 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); // This paint should only update B. C should still be dehydrated. 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); }); // Finally we can hydrate C 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); }, ); });