Test showing that a mismatch at the root recovers with client render but shows loading state (#22873)
* rm console.log * gate test * move test * show fallback state
salazarm committed
Dec 6, 2021 at 12:36 UTC
c7917fe76982c499c81be9571de44fe1293ac893
1 file changed
+63
packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js
+63
@@ -3014,4 +3014,67 @@ describe('ReactDOMServerPartialHydration', () => {
3014
);
3015
3016
itHydratesWithoutMismatch('an empty string in class component', TestAppClass);
3017
+
3018
+ // @gate enableClientRenderFallbackOnHydrationMismatch
3019
+ it('fallback to client render on hydration mismatch at root', async () => {
3020
+ let isClient = false;
3021
+ let suspend = true;
3022
+ let resolve;
3023
+ const promise = new Promise((res, rej) => {
3024
+ resolve = () => {
3025
+ suspend = false;
3026
+ res();
3027
+ };
3028
+ });
3029
+ function App() {
3030
+ return (
3031
+ <>
3032
+ <Suspense fallback={<div>Loading</div>}>
3033
+ <ChildThatSuspends id={1} />
3034
+ </Suspense>
3035
+ {isClient ? <span>client</span> : <div>server</div>}
3036
+ <Suspense fallback={<div>Loading</div>}>
3037
+ <ChildThatSuspends id={2} />
3038
+ </Suspense>
3039
+ </>
3040
+ );
3041
+ }
3042
+ function ChildThatSuspends({id}) {
3043
+ if (isClient && suspend) {
3044
+ throw promise;
3045
+ }
3046
+ return <div>{id}</div>;
3047
+ }
3048
+
3049
+ const finalHTML = ReactDOMServer.renderToString(<App />);
3050
+
3051
+ const container = document.createElement('div');
3052
+ document.body.appendChild(container);
3053
+ container.innerHTML = finalHTML;
3054
+ isClient = true;
3055
+
3056
+ expect(() => {
3057
+ act(() => {
3058
+ ReactDOM.hydrateRoot(container, <App />);
3059
+ });
3060
+ }).toErrorDev(
3061
+ 'Warning: An error occurred during hydration. ' +
3062
+ 'The server HTML was replaced with client content in <div>.',
3063
+ {withoutStack: true},
3064
+ );
3065
+
3066
+ // We show fallback state when mismatch happens at root
3067
+ expect(container.innerHTML).toEqual(
3068
+ '<div>Loading</div><span>client</span><div>Loading</div>',
3069
+ );
3070
+
3071
+ await act(async () => {
3072
+ resolve();
3073
+ await promise;
3074
+ });
3075
+
3076
+ expect(container.innerHTML).toEqual(
3077
+ '<div>1</div><span>client</span><div>2</div>',
3078
+ );
3079
+ });
3080
});