Skip to content

Commit ea04cb9

Browse files
committed
Test
1 parent 5707101 commit ea04cb9

File tree

1 file changed

+331
-0
lines changed

1 file changed

+331
-0
lines changed
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @emails react-core
8+
* @jest-environment ./scripts/jest/ReactDOMServerIntegrationEnvironment
9+
*/
10+
11+
'use strict';
12+
import {
13+
insertNodesAndExecuteScripts,
14+
getVisibleChildren,
15+
} from '../test-utils/FizzTestUtils';
16+
17+
let JSDOM;
18+
let React;
19+
let Suspense;
20+
let ViewTransition;
21+
let ReactDOMClient;
22+
let clientAct;
23+
let ReactDOMFizzServer;
24+
let Stream;
25+
let document;
26+
let writable;
27+
let container;
28+
let buffer = '';
29+
let hasErrored = false;
30+
let fatalError = undefined;
31+
32+
describe('ReactDOMFizzViewTransition', () => {
33+
beforeEach(() => {
34+
jest.resetModules();
35+
JSDOM = require('jsdom').JSDOM;
36+
React = require('react');
37+
ReactDOMClient = require('react-dom/client');
38+
clientAct = require('internal-test-utils').act;
39+
ReactDOMFizzServer = require('react-dom/server');
40+
Stream = require('stream');
41+
42+
Suspense = React.Suspense;
43+
ViewTransition = React.unstable_ViewTransition;
44+
45+
// Test Environment
46+
const jsdom = new JSDOM(
47+
'<!DOCTYPE html><html><head></head><body><div id="container">',
48+
{
49+
runScripts: 'dangerously',
50+
},
51+
);
52+
document = jsdom.window.document;
53+
container = document.getElementById('container');
54+
55+
buffer = '';
56+
hasErrored = false;
57+
58+
writable = new Stream.PassThrough();
59+
writable.setEncoding('utf8');
60+
writable.on('data', chunk => {
61+
buffer += chunk;
62+
});
63+
writable.on('error', error => {
64+
hasErrored = true;
65+
fatalError = error;
66+
});
67+
});
68+
69+
afterEach(() => {
70+
jest.restoreAllMocks();
71+
});
72+
73+
async function serverAct(callback) {
74+
await callback();
75+
// Await one turn around the event loop.
76+
// This assumes that we'll flush everything we have so far.
77+
await new Promise(resolve => {
78+
setImmediate(resolve);
79+
});
80+
if (hasErrored) {
81+
throw fatalError;
82+
}
83+
// JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
84+
// We also want to execute any scripts that are embedded.
85+
// We assume that we have now received a proper fragment of HTML.
86+
const bufferedContent = buffer;
87+
buffer = '';
88+
const temp = document.createElement('body');
89+
temp.innerHTML = bufferedContent;
90+
await insertNodesAndExecuteScripts(temp, container, null);
91+
jest.runAllTimers();
92+
}
93+
94+
// @gate enableViewTransition
95+
it('emits annotations for view transitions', async () => {
96+
function App() {
97+
return (
98+
<div>
99+
<ViewTransition>
100+
<div />
101+
</ViewTransition>
102+
<ViewTransition name="foo" update="bar">
103+
<div />
104+
</ViewTransition>
105+
<ViewTransition update={{something: 'a', default: 'baz'}}>
106+
<div />
107+
</ViewTransition>
108+
<ViewTransition name="outer" update="bar" share="pair">
109+
<ViewTransition>
110+
<div />
111+
</ViewTransition>
112+
</ViewTransition>
113+
</div>
114+
);
115+
}
116+
117+
await serverAct(async () => {
118+
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
119+
pipe(writable);
120+
});
121+
122+
expect(getVisibleChildren(container)).toEqual(
123+
<div>
124+
<div vt-update="auto" />
125+
<div vt-name="foo" vt-update="bar" vt-share="auto" />
126+
<div vt-update="baz" />
127+
<div vt-name="outer" vt-update="auto" vt-share="pair" />
128+
</div>,
129+
);
130+
131+
// Hydration should not yield any errors.
132+
await clientAct(async () => {
133+
ReactDOMClient.hydrateRoot(container, <App />);
134+
});
135+
});
136+
137+
// @gate enableViewTransition
138+
it('emits enter/exit annotations for view transitions inside Suspense', async () => {
139+
let resolve;
140+
const promise = new Promise(r => (resolve = r));
141+
function Suspend() {
142+
return React.use(promise);
143+
}
144+
function App() {
145+
const fallback = (
146+
<ViewTransition>
147+
<div>
148+
<ViewTransition>
149+
<span>Loading</span>
150+
</ViewTransition>
151+
</div>
152+
</ViewTransition>
153+
);
154+
return (
155+
<div>
156+
<Suspense fallback={fallback}>
157+
<ViewTransition>
158+
<Suspend />
159+
</ViewTransition>
160+
</Suspense>
161+
</div>
162+
);
163+
}
164+
165+
await serverAct(async () => {
166+
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
167+
pipe(writable);
168+
});
169+
170+
expect(getVisibleChildren(container)).toEqual(
171+
<div>
172+
<div vt-update="auto" vt-exit="auto">
173+
<span vt-update="auto">Loading</span>
174+
</div>
175+
</div>,
176+
);
177+
178+
await serverAct(async () => {
179+
await resolve(
180+
<div>
181+
<ViewTransition>
182+
<span>Content</span>
183+
</ViewTransition>
184+
</div>,
185+
);
186+
});
187+
188+
expect(getVisibleChildren(container)).toEqual(
189+
<div>
190+
<div vt-update="auto" vt-enter="auto">
191+
<span vt-update="auto">Content</span>
192+
</div>
193+
</div>,
194+
);
195+
196+
// Hydration should not yield any errors.
197+
await clientAct(async () => {
198+
ReactDOMClient.hydrateRoot(container, <App />);
199+
});
200+
});
201+
202+
// @gate enableViewTransition
203+
it('can emit both enter and exit on the same node', async () => {
204+
let resolve;
205+
const promise = new Promise(r => (resolve = r));
206+
function Suspend() {
207+
return React.use(promise);
208+
}
209+
function App() {
210+
const fallback = (
211+
<Suspense fallback={null}>
212+
<ViewTransition enter="hello" exit="goodbye">
213+
<div>
214+
<ViewTransition>
215+
<span>Loading</span>
216+
</ViewTransition>
217+
</div>
218+
</ViewTransition>
219+
</Suspense>
220+
);
221+
return (
222+
<div>
223+
<Suspense fallback={fallback}>
224+
<ViewTransition enter="hi">
225+
<Suspend />
226+
</ViewTransition>
227+
</Suspense>
228+
</div>
229+
);
230+
}
231+
232+
await serverAct(async () => {
233+
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
234+
pipe(writable);
235+
});
236+
237+
expect(getVisibleChildren(container)).toEqual(
238+
<div>
239+
<div vt-update="auto" vt-enter="hello" vt-exit="goodbye">
240+
<span vt-update="auto">Loading</span>
241+
</div>
242+
</div>,
243+
);
244+
245+
await serverAct(async () => {
246+
await resolve(
247+
<div>
248+
<ViewTransition>
249+
<span>Content</span>
250+
</ViewTransition>
251+
</div>,
252+
);
253+
});
254+
255+
expect(getVisibleChildren(container)).toEqual(
256+
<div>
257+
<div vt-update="auto" vt-enter="hi">
258+
<span vt-update="auto">Content</span>
259+
</div>
260+
</div>,
261+
);
262+
263+
// Hydration should not yield any errors.
264+
await clientAct(async () => {
265+
ReactDOMClient.hydrateRoot(container, <App />);
266+
});
267+
});
268+
269+
// @gate enableViewTransition
270+
it('emits annotations for view transitions outside Suspense', async () => {
271+
let resolve;
272+
const promise = new Promise(r => (resolve = r));
273+
function Suspend() {
274+
return React.use(promise);
275+
}
276+
function App() {
277+
const fallback = (
278+
<div>
279+
<ViewTransition>
280+
<span>Loading</span>
281+
</ViewTransition>
282+
</div>
283+
);
284+
return (
285+
<div>
286+
<ViewTransition>
287+
<Suspense fallback={fallback}>
288+
<Suspend />
289+
</Suspense>
290+
</ViewTransition>
291+
</div>
292+
);
293+
}
294+
295+
await serverAct(async () => {
296+
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
297+
pipe(writable);
298+
});
299+
300+
expect(getVisibleChildren(container)).toEqual(
301+
<div>
302+
<div vt-name="«R0»" vt-update="auto" vt-share="auto">
303+
<span vt-update="auto">Loading</span>
304+
</div>
305+
</div>,
306+
);
307+
308+
await serverAct(async () => {
309+
await resolve(
310+
<div>
311+
<ViewTransition>
312+
<span>Content</span>
313+
</ViewTransition>
314+
</div>,
315+
);
316+
});
317+
318+
expect(getVisibleChildren(container)).toEqual(
319+
<div>
320+
<div vt-name="«R0»" vt-update="auto" vt-share="auto">
321+
<span vt-update="auto">Content</span>
322+
</div>
323+
</div>,
324+
);
325+
326+
// Hydration should not yield any errors.
327+
await clientAct(async () => {
328+
ReactDOMClient.hydrateRoot(container, <App />);
329+
});
330+
});
331+
});

0 commit comments

Comments
 (0)