main
js 156 lines 3.97 KB
Raw
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 node
9 */
10
11 'use strict';
12
13 let React;
14 let ReactTestRenderer;
15 let Scheduler;
16 let waitForAll;
17 let waitFor;
18
19 describe('ReactTestRendererAsync', () => {
20 beforeEach(() => {
21 jest.resetModules();
22
23 React = require('react');
24 ReactTestRenderer = require('react-test-renderer');
25 Scheduler = require('scheduler');
26
27 const InternalTestUtils = require('internal-test-utils');
28 waitForAll = InternalTestUtils.waitForAll;
29 waitFor = InternalTestUtils.waitFor;
30 });
31
32 it('flushAll flushes all work', async () => {
33 function Foo(props) {
34 return props.children;
35 }
36 const renderer = ReactTestRenderer.create(<Foo>Hi</Foo>, {
37 unstable_isConcurrent: true,
38 });
39
40 // Before flushing, nothing has mounted.
41 expect(renderer.toJSON()).toEqual(null);
42
43 // Flush initial mount.
44 await waitForAll([]);
45 expect(renderer.toJSON()).toEqual('Hi');
46
47 // Update
48 renderer.update(<Foo>Bye</Foo>);
49 // Not yet updated.
50 expect(renderer.toJSON()).toEqual('Hi');
51 // Flush update.
52 await waitForAll([]);
53 expect(renderer.toJSON()).toEqual('Bye');
54 });
55
56 it('flushAll returns array of yielded values', async () => {
57 function Child(props) {
58 Scheduler.log(props.children);
59 return props.children;
60 }
61 function Parent(props) {
62 return (
63 <>
64 <Child>{'A:' + props.step}</Child>
65 <Child>{'B:' + props.step}</Child>
66 <Child>{'C:' + props.step}</Child>
67 </>
68 );
69 }
70 const renderer = ReactTestRenderer.create(<Parent step={1} />, {
71 unstable_isConcurrent: true,
72 });
73
74 await waitForAll(['A:1', 'B:1', 'C:1']);
75 expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
76
77 renderer.update(<Parent step={2} />);
78 await waitForAll(['A:2', 'B:2', 'C:2']);
79 expect(renderer.toJSON()).toEqual(['A:2', 'B:2', 'C:2']);
80 });
81
82 it('flushThrough flushes until the expected values is yielded', async () => {
83 function Child(props) {
84 Scheduler.log(props.children);
85 return props.children;
86 }
87 function Parent(props) {
88 return (
89 <>
90 <Child>{'A:' + props.step}</Child>
91 <Child>{'B:' + props.step}</Child>
92 <Child>{'C:' + props.step}</Child>
93 </>
94 );
95 }
96
97 let renderer;
98 React.startTransition(() => {
99 renderer = ReactTestRenderer.create(<Parent step={1} />, {
100 unstable_isConcurrent: true,
101 });
102 });
103
104 // Flush the first two siblings
105 await waitFor(['A:1', 'B:1']);
106 // Did not commit yet.
107 expect(renderer.toJSON()).toEqual(null);
108
109 // Flush the remaining work
110 await waitForAll(['C:1']);
111 expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
112 });
113
114 it('supports high priority interruptions', async () => {
115 function Child(props) {
116 Scheduler.log(props.children);
117 return props.children;
118 }
119
120 class Example extends React.Component {
121 componentDidMount() {
122 expect(this.props.step).toEqual(2);
123 }
124 componentDidUpdate() {
125 throw Error('Unexpected update');
126 }
127 render() {
128 return (
129 <>
130 <Child>{'A:' + this.props.step}</Child>
131 <Child>{'B:' + this.props.step}</Child>
132 </>
133 );
134 }
135 }
136
137 let renderer;
138 React.startTransition(() => {
139 renderer = ReactTestRenderer.create(<Example step={1} />, {
140 unstable_isConcurrent: true,
141 });
142 });
143
144 // Flush the some of the changes, but don't commit
145 await waitFor(['A:1']);
146 expect(renderer.toJSON()).toEqual(null);
147
148 // Interrupt with higher priority properties
149 renderer.unstable_flushSync(() => {
150 renderer.update(<Example step={2} />);
151 });
152
153 // Only the higher priority properties have been committed
154 expect(renderer.toJSON()).toEqual(['A:2', 'B:2']);
155 });
156 });