mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[ServerRenderer] Setup for adding data attributes streaming format (#25567)
This commit is contained in:
+99
-123
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
import {replaceScriptsAndMove, mergeOptions} from '../test-utils/FizzTestUtils';
|
||||
|
||||
let JSDOM;
|
||||
let Stream;
|
||||
@@ -30,6 +31,7 @@ let container;
|
||||
let buffer = '';
|
||||
let hasErrored = false;
|
||||
let fatalError = undefined;
|
||||
const renderOptions = {};
|
||||
|
||||
describe('ReactDOMFizzServer', () => {
|
||||
beforeEach(() => {
|
||||
@@ -134,17 +136,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
container.nodeName === '#document' ? container.body : container;
|
||||
while (fakeBody.firstChild) {
|
||||
const node = fakeBody.firstChild;
|
||||
if (
|
||||
node.nodeName === 'SCRIPT' &&
|
||||
(CSPnonce === null || node.getAttribute('nonce') === CSPnonce)
|
||||
) {
|
||||
const script = document.createElement('script');
|
||||
script.textContent = node.textContent;
|
||||
fakeBody.removeChild(node);
|
||||
parent.appendChild(script);
|
||||
} else {
|
||||
parent.appendChild(node);
|
||||
}
|
||||
await replaceScriptsAndMove(window, CSPnonce, node, parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +162,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
document = jsdom.window.document;
|
||||
container = document;
|
||||
buffer = '';
|
||||
await replaceScriptsAndMove(window, CSPnonce, document.documentElement);
|
||||
}
|
||||
|
||||
function getVisibleChildren(element) {
|
||||
@@ -179,6 +172,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
if (node.nodeType === 1) {
|
||||
if (
|
||||
node.tagName !== 'SCRIPT' &&
|
||||
node.tagName !== 'script' &&
|
||||
node.tagName !== 'TEMPLATE' &&
|
||||
node.tagName !== 'template' &&
|
||||
!node.hasAttribute('hidden') &&
|
||||
@@ -288,6 +282,13 @@ describe('ReactDOMFizzServer', () => {
|
||||
const As = as;
|
||||
return <As>{readText(text)}</As>;
|
||||
}
|
||||
function renderToPipeableStream(jsx, options) {
|
||||
// Merge options with renderOptions, which may contain featureFlag specific behavior
|
||||
return ReactDOMFizzServer.renderToPipeableStream(
|
||||
jsx,
|
||||
mergeOptions(options, renderOptions),
|
||||
);
|
||||
}
|
||||
|
||||
it('should asynchronously load a lazy component', async () => {
|
||||
let resolveA;
|
||||
@@ -313,7 +314,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
};
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<div>
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
@@ -379,7 +380,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
// Server-side
|
||||
const [App, resolve] = makeApp();
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
@@ -432,7 +433,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
<Lazy text="Hello" />
|
||||
@@ -492,13 +493,10 @@ describe('ReactDOMFizzServer', () => {
|
||||
loggedErrors.length = 0;
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App isClient={false} />,
|
||||
{
|
||||
bootstrapScriptContent: '__INIT__();',
|
||||
onError,
|
||||
},
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<App isClient={false} />, {
|
||||
bootstrapScriptContent: '__INIT__();',
|
||||
onError,
|
||||
});
|
||||
pipe(writable);
|
||||
});
|
||||
expect(loggedErrors).toEqual([]);
|
||||
@@ -554,7 +552,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
{lazyElement}
|
||||
@@ -567,7 +565,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
// Because there is no content inside the Suspense boundary that could've
|
||||
// been written, we expect to not see any additional partial data flushed
|
||||
// yet.
|
||||
expect(container.firstChild.nextSibling).toBe(null);
|
||||
expect(container.childNodes.length).toBe(1);
|
||||
await act(async () => {
|
||||
resolveElement({default: <Text text="Hello" />});
|
||||
});
|
||||
@@ -603,7 +601,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App isClient={false} />,
|
||||
|
||||
{
|
||||
@@ -699,7 +697,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
loggedErrors.length = 0;
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App />,
|
||||
|
||||
{
|
||||
@@ -767,7 +765,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
loggedErrors.length = 0;
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App />,
|
||||
|
||||
{
|
||||
@@ -823,7 +821,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
it('should asynchronously load the suspense boundary', async () => {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
<AsyncText text="Hello World" />
|
||||
@@ -862,7 +860,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
};
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
bootstrapScriptContent: '__INIT__();',
|
||||
});
|
||||
pipe(writable);
|
||||
@@ -936,7 +934,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
// We originally suspend the boundary and start streaming the loading state.
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App />,
|
||||
|
||||
{
|
||||
@@ -1018,9 +1016,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
// We originally suspend the boundary and start streaming the loading state.
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App showMore={false} />,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<App showMore={false} />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -1093,7 +1089,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
let controls;
|
||||
await act(async () => {
|
||||
controls = ReactDOMFizzServer.renderToPipeableStream(<App />, {onError});
|
||||
controls = renderToPipeableStream(<App />, {onError});
|
||||
controls.pipe(writable);
|
||||
});
|
||||
|
||||
@@ -1163,7 +1159,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
};
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
// We use two nested boundaries to flush out coverage of an old reentrancy bug.
|
||||
<Suspense fallback="Loading...">
|
||||
<Suspense fallback={<Text text="Loading A..." />}>
|
||||
@@ -1187,7 +1183,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<Suspense fallback={<Text text="Loading B..." />}>
|
||||
<Text text="This will show B: " />
|
||||
<div>
|
||||
@@ -1283,7 +1279,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -1370,7 +1366,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -1423,7 +1419,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App />,
|
||||
|
||||
{
|
||||
@@ -1509,7 +1505,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
try {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<A />);
|
||||
const {pipe} = renderToPipeableStream(<A />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -1607,7 +1603,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<TestProvider ctx="A">
|
||||
<div>
|
||||
<Suspense fallback={[<Text text="Loading: " />, <TestConsumer />]}>
|
||||
@@ -1664,7 +1660,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<PrintA />
|
||||
<div>
|
||||
@@ -1725,7 +1721,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
const loggedErrors = [];
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<PrintA />
|
||||
<div>
|
||||
@@ -1793,7 +1789,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
let controls;
|
||||
await act(async () => {
|
||||
controls = ReactDOMFizzServer.renderToPipeableStream(
|
||||
controls = renderToPipeableStream(
|
||||
<App isClient={false} />,
|
||||
|
||||
{
|
||||
@@ -1876,7 +1872,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
it('should be able to abort the fallback if the main content finishes first', async () => {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<Suspense fallback={<Text text="Loading Outer" />}>
|
||||
<div>
|
||||
<Suspense
|
||||
@@ -1973,9 +1969,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await jest.runAllTimers();
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App isClient={false} />,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<App isClient={false} />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -2085,7 +2079,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
const loggedErrors = [];
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<Suspense fallback="Loading...">
|
||||
<App />
|
||||
</Suspense>,
|
||||
@@ -2170,7 +2164,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
const loggedErrors = [];
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<Suspense fallback="Loading...">
|
||||
<App />
|
||||
</Suspense>,
|
||||
@@ -2259,7 +2253,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
@@ -2349,7 +2343,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
@@ -2439,7 +2433,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
@@ -2492,7 +2486,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
}
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
onError(error) {
|
||||
Scheduler.unstable_yieldValue('[s!] ' + error.message);
|
||||
},
|
||||
@@ -2577,14 +2571,11 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
}
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App color="red" />,
|
||||
{
|
||||
onError(error) {
|
||||
Scheduler.unstable_yieldValue('[s!] ' + error.message);
|
||||
},
|
||||
const {pipe} = renderToPipeableStream(<App color="red" />, {
|
||||
onError(error) {
|
||||
Scheduler.unstable_yieldValue('[s!] ' + error.message);
|
||||
},
|
||||
);
|
||||
});
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['[s!] Oops.']);
|
||||
@@ -2678,7 +2669,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App fallbackText="Loading..." />,
|
||||
{
|
||||
onError(error) {
|
||||
@@ -2807,7 +2798,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
@@ -2959,7 +2950,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A', 'B']);
|
||||
@@ -3025,7 +3016,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<Foo />);
|
||||
const {pipe} = renderToPipeableStream(<Foo />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -3047,9 +3038,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
]).map(item => <li key={item.get('value')}>{item.get('name')}</li>);
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<ul>{mappedJSX}</ul>,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<ul>{mappedJSX}</ul>);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
@@ -3081,10 +3070,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
let abort;
|
||||
const loggedErrors = [];
|
||||
await act(async () => {
|
||||
const {
|
||||
pipe,
|
||||
abort: abortImpl,
|
||||
} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe, abort: abortImpl} = renderToPipeableStream(<App />, {
|
||||
onError(error) {
|
||||
// In this test we contrive erroring with strings so we push the error whereas in most
|
||||
// other tests we contrive erroring with Errors and push the message.
|
||||
@@ -3167,10 +3153,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
let abort;
|
||||
const loggedErrors = [];
|
||||
await act(async () => {
|
||||
const {
|
||||
pipe,
|
||||
abort: abortImpl,
|
||||
} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe, abort: abortImpl} = renderToPipeableStream(<App />, {
|
||||
onError(error) {
|
||||
loggedErrors.push(error.message);
|
||||
return 'a digest';
|
||||
@@ -3232,7 +3215,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
it('warns in dev if you access digest from errorInfo in onRecoverableError', async () => {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<div>
|
||||
<Suspense fallback={'loading...'}>
|
||||
<AsyncText text={'hello'} />
|
||||
@@ -3309,7 +3292,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
onError,
|
||||
});
|
||||
pipe(writable);
|
||||
@@ -3357,7 +3340,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
onError,
|
||||
});
|
||||
pipe(writable);
|
||||
@@ -3397,7 +3380,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
loggedErrors.length = 0;
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
onError,
|
||||
});
|
||||
pipe(writable);
|
||||
@@ -3435,7 +3418,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
it('accepts an integrity property for bootstrapScripts and bootstrapModules', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3494,7 +3477,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
const stringWithScriptsInIt =
|
||||
'prescription pre<scription pre<Scription pre</scRipTion pre</ScripTion </script><script><!-- <script> -->';
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<div />, {
|
||||
const {pipe} = renderToPipeableStream(<div />, {
|
||||
bootstrapScriptContent:
|
||||
'window.__test_outlet = "This should have been replaced";var x = "' +
|
||||
stringWithScriptsInIt +
|
||||
@@ -3515,7 +3498,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
el.textContent = '{"one":1,\u2028\u2029"two":2}';
|
||||
const stringWithLSAndPSCharacters = el.textContent;
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<div />, {
|
||||
const {pipe} = renderToPipeableStream(<div />, {
|
||||
bootstrapScriptContent:
|
||||
'let x = ' +
|
||||
stringWithLSAndPSCharacters +
|
||||
@@ -3536,7 +3519,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
// this boolean expression will be cast to a number due to the bitwise &. we will look for a truthy value (1) below
|
||||
const booleanLogicString = '1 < 2 & 3 > 1';
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<div />, {
|
||||
const {pipe} = renderToPipeableStream(<div />, {
|
||||
bootstrapScriptContent:
|
||||
'let x = ' + booleanLogicString + '; window.__test_outlet = x;',
|
||||
});
|
||||
@@ -3549,7 +3532,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
// @gate enableFizzExternalRuntime
|
||||
it('supports option to load runtime as an external script', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3608,7 +3591,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
const [ServerApp, serverResolve] = makeApp();
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<ServerApp />);
|
||||
const {pipe} = renderToPipeableStream(<ServerApp />);
|
||||
pipe(writable);
|
||||
});
|
||||
await act(() => {
|
||||
@@ -3684,9 +3667,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
const [ServerApp, serverResolve] = makeApp();
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<ServerApp text="initial" />,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<ServerApp text="initial" />);
|
||||
pipe(writable);
|
||||
});
|
||||
await act(() => {
|
||||
@@ -3763,9 +3744,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
try {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App text="initial" />,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<App text="initial" />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -3854,7 +3833,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
};
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -3946,7 +3925,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
try {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4077,7 +4056,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
try {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4200,7 +4179,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
try {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4271,7 +4250,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
}
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4317,7 +4296,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
}
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4372,7 +4351,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html data-html="html">
|
||||
<AsyncNoOutput />
|
||||
<AsyncHead />
|
||||
@@ -4413,7 +4392,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -4470,9 +4449,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App name="Foo" />,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<App name="Foo" />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4510,9 +4487,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
<App name="Foo" />,
|
||||
);
|
||||
const {pipe} = renderToPipeableStream(<App name="Foo" />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4562,7 +4537,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -4607,7 +4582,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
await afterImmediate();
|
||||
await act(() => resolveText('ello'));
|
||||
pipe(writable);
|
||||
@@ -4651,7 +4626,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
await afterImmediate();
|
||||
await act(() => resolveText('world'));
|
||||
pipe(writable);
|
||||
@@ -4689,7 +4664,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
await afterImmediate();
|
||||
await act(() => resolveText('world'));
|
||||
pipe(writable);
|
||||
@@ -4738,7 +4713,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
await afterImmediate();
|
||||
await act(() => resolveText('world'));
|
||||
pipe(writable);
|
||||
@@ -4823,12 +4798,13 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
await afterImmediate();
|
||||
await act(() => resolveText('world'));
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
// strip inserted external runtime
|
||||
expect(container.innerHTML).toEqual(
|
||||
'<div><!--$-->hello<!-- -->world<!-- --><!--/$--><!--$-->world<!-- --><!--/$--><!--$-->hello<!-- -->world<!-- --><br><!--/$--><!--$-->world<!-- --><br><!--/$--></div>',
|
||||
);
|
||||
@@ -4879,7 +4855,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
prepareJSDOMForTitle();
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
|
||||
@@ -4903,7 +4879,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
prepareJSDOMForTitle();
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
|
||||
@@ -4941,7 +4917,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
prepareJSDOMForTitle();
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
if (__DEV__) {
|
||||
@@ -5025,7 +5001,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
prepareJSDOMForTitle();
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
if (__DEV__) {
|
||||
@@ -5086,7 +5062,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -5146,7 +5122,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
|
||||
@@ -5185,7 +5161,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -5254,7 +5230,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
const reportedServerErrors = [];
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
onError(error) {
|
||||
reportedServerErrors.push(error);
|
||||
},
|
||||
@@ -5315,7 +5291,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual('Hi');
|
||||
@@ -5342,7 +5318,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
}
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(<button>0</button>);
|
||||
@@ -5373,7 +5349,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
let caughtError;
|
||||
try {
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />, {
|
||||
const {pipe} = renderToPipeableStream(<App />, {
|
||||
onError(e) {
|
||||
reportedServerErrors.push(e);
|
||||
},
|
||||
@@ -5402,7 +5378,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
}
|
||||
}
|
||||
await act(async () => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getVisibleChildren(container)).toEqual(<div />);
|
||||
|
||||
+58
-55
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
import {replaceScriptsAndMove, mergeOptions} from '../test-utils/FizzTestUtils';
|
||||
|
||||
let JSDOM;
|
||||
let Stream;
|
||||
@@ -25,6 +26,7 @@ let container;
|
||||
let buffer = '';
|
||||
let hasErrored = false;
|
||||
let fatalError = undefined;
|
||||
const renderOptions = {};
|
||||
|
||||
describe('ReactDOMFloat', () => {
|
||||
beforeEach(() => {
|
||||
@@ -100,17 +102,7 @@ describe('ReactDOMFloat', () => {
|
||||
container.nodeName === '#document' ? container.body : container;
|
||||
while (fakeBody.firstChild) {
|
||||
const node = fakeBody.firstChild;
|
||||
if (
|
||||
node.nodeName === 'SCRIPT' &&
|
||||
(CSPnonce === null || node.getAttribute('nonce') === CSPnonce)
|
||||
) {
|
||||
const script = document.createElement('script');
|
||||
script.textContent = node.textContent;
|
||||
fakeBody.removeChild(node);
|
||||
parent.appendChild(script);
|
||||
} else {
|
||||
parent.appendChild(node);
|
||||
}
|
||||
await replaceScriptsAndMove(document.defaultView, CSPnonce, node, parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +127,7 @@ describe('ReactDOMFloat', () => {
|
||||
document = jsdom.window.document;
|
||||
container = document;
|
||||
buffer = '';
|
||||
await replaceScriptsAndMove(jsdom.window, null, document.documentElement);
|
||||
}
|
||||
|
||||
function getMeaningfulChildren(element) {
|
||||
@@ -148,6 +141,8 @@ describe('ReactDOMFloat', () => {
|
||||
node.hasAttribute('data-meaningful') ||
|
||||
(node.tagName === 'SCRIPT' &&
|
||||
node.hasAttribute('src') &&
|
||||
node.getAttribute('src') !==
|
||||
renderOptions.unstable_externalRuntimeSrc &&
|
||||
node.hasAttribute('async')) ||
|
||||
(node.tagName !== 'SCRIPT' &&
|
||||
node.tagName !== 'TEMPLATE' &&
|
||||
@@ -235,6 +230,14 @@ describe('ReactDOMFloat', () => {
|
||||
return readText(text);
|
||||
}
|
||||
|
||||
function renderToPipeableStream(jsx, options) {
|
||||
// Merge options with renderOptions, which may contain featureFlag specific behavior
|
||||
return ReactDOMFizzServer.renderToPipeableStream(
|
||||
jsx,
|
||||
mergeOptions(options, renderOptions),
|
||||
);
|
||||
}
|
||||
|
||||
// @gate enableFloat
|
||||
it('can render resources before singletons', async () => {
|
||||
const root = ReactDOMClient.createRoot(document);
|
||||
@@ -569,7 +572,7 @@ describe('ReactDOMFloat', () => {
|
||||
});
|
||||
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<title>foo</title>
|
||||
<html>
|
||||
@@ -635,7 +638,7 @@ describe('ReactDOMFloat', () => {
|
||||
return 'foo';
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -786,7 +789,7 @@ describe('ReactDOMFloat', () => {
|
||||
}
|
||||
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<ServerApp />);
|
||||
const {pipe} = renderToPipeableStream(<ServerApp />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
@@ -846,7 +849,7 @@ describe('ReactDOMFloat', () => {
|
||||
return 'foo';
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -877,7 +880,7 @@ describe('ReactDOMFloat', () => {
|
||||
return 'foo';
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -996,7 +999,7 @@ describe('ReactDOMFloat', () => {
|
||||
);
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<App srcs={['server', 'shared']} />,
|
||||
);
|
||||
pipe(writable);
|
||||
@@ -1148,7 +1151,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('supports preconnects, prefetc-dns, and arbitrary other link types', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -1259,7 +1262,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can render <base> as a Resource', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -1317,7 +1320,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can render icons and apple-touch-icons as Resources', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<html>
|
||||
<head />
|
||||
@@ -1371,7 +1374,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can hydrate the right instances for deeply nested structured metas', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<html>
|
||||
<head />
|
||||
@@ -1463,7 +1466,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can insert meta tags in the expected location', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<html>
|
||||
<head />
|
||||
@@ -1615,7 +1618,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can render meta tags with og properties with structured data', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<html>
|
||||
<head />
|
||||
@@ -1778,7 +1781,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can render meta tags as resources', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<html>
|
||||
<head />
|
||||
@@ -1843,7 +1846,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('can rendering title tags anywhere in the tree', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<title>before</title>
|
||||
<>
|
||||
@@ -1918,7 +1921,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('prepends new titles on the client so newer ones override older ones, including orphaned server rendered titles', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<title>server</title>
|
||||
@@ -2032,7 +2035,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat && enableHostSingletons && (enableClientRenderFallbackOnTextMismatch || !__DEV__)
|
||||
it('can render a title before a singleton even if that singleton clears its contents', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<>
|
||||
<title>foo</title>
|
||||
<html>
|
||||
@@ -2097,7 +2100,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('treats link rel stylesheet elements as a style resource when it includes a precedence when server rendering', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2150,7 +2153,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('treats link rel stylesheet elements as a style resource when it includes a precedence when hydrating', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2188,7 +2191,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('preloads stylesheets without a precedence prop when server rendering', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2216,7 +2219,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('hoists style resources to the correct precedence', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2311,7 +2314,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat && enableHostSingletons && enableClientRenderFallbackOnTextMismatch
|
||||
it('retains styles even when a new html, head, and/body mount', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2363,7 +2366,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat && !enableHostSingletons
|
||||
it('retains styles even when a new html, head, and/body mount - without HostSingleton', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2468,7 +2471,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('treats async scripts without onLoad or onError as Resources', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2553,7 +2556,7 @@ describe('ReactDOMFloat', () => {
|
||||
);
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
|
||||
@@ -2636,7 +2639,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('treats stylesheet links with a precedence as a resource', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2689,7 +2692,7 @@ describe('ReactDOMFloat', () => {
|
||||
}
|
||||
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -2745,7 +2748,7 @@ describe('ReactDOMFloat', () => {
|
||||
ReactDOM.preinit('preset', {as: 'style', precedence: 'preset'});
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3109,7 +3112,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('normalizes style resource precedence for all boundaries inlined as part of the shell flush', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3199,7 +3202,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('style resources are inserted according to precedence order on the client', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3328,7 +3331,7 @@ describe('ReactDOMFloat', () => {
|
||||
return null;
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3406,7 +3409,7 @@ describe('ReactDOMFloat', () => {
|
||||
return children;
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3529,7 +3532,7 @@ describe('ReactDOMFloat', () => {
|
||||
return children;
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3761,7 +3764,7 @@ describe('ReactDOMFloat', () => {
|
||||
}
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
@@ -3869,7 +3872,7 @@ describe('ReactDOMFloat', () => {
|
||||
return children;
|
||||
}
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -3998,7 +4001,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -4082,7 +4085,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<Component scenarios={scenarios} />
|
||||
@@ -4719,7 +4722,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
@@ -4832,7 +4835,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
@@ -4945,7 +4948,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
@@ -5056,7 +5059,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<script src="foo" async={true} data-foo="a current value" />
|
||||
@@ -5106,7 +5109,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
@@ -5201,7 +5204,7 @@ describe('ReactDOMFloat', () => {
|
||||
};
|
||||
try {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
@@ -5262,7 +5265,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('escapes hrefs when selecting matching elements in the document when rendering Resources', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
@@ -5324,7 +5327,7 @@ describe('ReactDOMFloat', () => {
|
||||
// @gate enableFloat
|
||||
it('escapes hrefs when selecting matching elements in the document when using preload and preinit', async () => {
|
||||
await actIntoEmptyDocument(() => {
|
||||
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
|
||||
const {pipe} = renderToPipeableStream(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
// TODO: Add Flow types
|
||||
/**
|
||||
* This file is compiled to a standalone browser script by rollup and loaded by Fizz
|
||||
* clients. Therefore, it should be fast and not have many external dependencies.
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// Imports are resolved statically by the closure compiler in release bundles
|
||||
// and by rollup in jest unit tests
|
||||
import {
|
||||
clientRenderBoundary,
|
||||
completeBoundaryWithStyles,
|
||||
completeBoundary,
|
||||
completeSegment,
|
||||
} from 'react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSet';
|
||||
} from '../../../react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSet';
|
||||
|
||||
// Intentionally does nothing. Implementation will be added in future PR.
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import * as tmp from 'tmp';
|
||||
import * as fs from 'fs';
|
||||
import replace from 'rollup-plugin-replace';
|
||||
import {rollup} from 'rollup';
|
||||
|
||||
const rollupCache: Map<string, string | null> = new Map();
|
||||
|
||||
// Utility function to read and bundle a standalone browser script
|
||||
async function getRollupResult(scriptSrc: string): Promise<string | null> {
|
||||
const cachedResult = rollupCache.get(scriptSrc);
|
||||
if (cachedResult !== undefined) {
|
||||
return cachedResult;
|
||||
}
|
||||
let tmpFile;
|
||||
try {
|
||||
tmpFile = tmp.fileSync();
|
||||
const rollupConfig = {
|
||||
input: require.resolve(scriptSrc),
|
||||
onwarn: console.warn,
|
||||
plugins: [replace({__DEV__: 'true'})],
|
||||
output: {
|
||||
externalLiveBindings: false,
|
||||
freeze: false,
|
||||
interop: false,
|
||||
esModule: false,
|
||||
},
|
||||
};
|
||||
const outputConfig = {
|
||||
file: tmpFile.name,
|
||||
format: 'iife',
|
||||
};
|
||||
const bundle = await rollup(rollupConfig);
|
||||
await bundle.write(outputConfig);
|
||||
const bundleBuffer = Buffer.alloc(4096);
|
||||
let bundleStr = '';
|
||||
while (true) {
|
||||
// $FlowFixMe[incompatible-call]
|
||||
const bytes = fs.readSync(tmpFile.fd, bundleBuffer);
|
||||
if (bytes <= 0) {
|
||||
break;
|
||||
}
|
||||
bundleStr += bundleBuffer.slice(0, bytes).toString();
|
||||
}
|
||||
rollupCache.set(scriptSrc, bundleStr);
|
||||
return bundleStr;
|
||||
} catch (e) {
|
||||
rollupCache.set(scriptSrc, null);
|
||||
return null;
|
||||
} finally {
|
||||
if (tmpFile) {
|
||||
tmpFile.removeCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function to process received HTML nodes and execute
|
||||
// embedded scripts by:
|
||||
// 1. Matching nonce attributes and moving node into an existing
|
||||
// parent container (if passed)
|
||||
// 2. Resolving scripts with sources
|
||||
async function replaceScriptsAndMove(
|
||||
window: any,
|
||||
CSPnonce: string | null,
|
||||
node: Node,
|
||||
parent: Node | null,
|
||||
) {
|
||||
if (
|
||||
node.nodeType === 1 &&
|
||||
(node.nodeName === 'SCRIPT' || node.nodeName === 'script')
|
||||
) {
|
||||
// $FlowFixMe[incompatible-cast]
|
||||
const element = (node: HTMLElement);
|
||||
const script = window.document.createElement('SCRIPT');
|
||||
const scriptSrc = element.getAttribute('src');
|
||||
if (scriptSrc) {
|
||||
const rollupOutput = await getRollupResult(scriptSrc);
|
||||
if (rollupOutput) {
|
||||
// Manually call eval(...) here, since changing the HTML text content
|
||||
// may interfere with hydration
|
||||
window.eval(rollupOutput);
|
||||
}
|
||||
for (let i = 0; i < element.attributes.length; i++) {
|
||||
const attr = element.attributes.item(i);
|
||||
script.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
} else if (element === null || element.getAttribute('nonce') === CSPnonce) {
|
||||
script.textContent = node.textContent;
|
||||
}
|
||||
if (parent) {
|
||||
element.parentNode?.removeChild(element);
|
||||
parent.appendChild(script);
|
||||
} else {
|
||||
element.parentNode?.replaceChild(script, element);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < node.childNodes.length; i++) {
|
||||
const inner = node.childNodes[i];
|
||||
await replaceScriptsAndMove(window, CSPnonce, inner, null);
|
||||
}
|
||||
if (parent != null) {
|
||||
parent.appendChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mergeOptions(options: Object, defaultOptions: Object): Object {
|
||||
return {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
export {replaceScriptsAndMove, mergeOptions};
|
||||
@@ -128,6 +128,8 @@ export const enableUseMemoCacheHook = __EXPERIMENTAL__;
|
||||
export const enableUseEventHook = __EXPERIMENTAL__;
|
||||
|
||||
// Test in www before enabling in open source.
|
||||
// Enables DOM-server to stream its instruction set as data-attributes
|
||||
// (handled with an MutationObserver) instead of inline-scripts
|
||||
export const enableFizzExternalRuntime = false;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user