@samitouri / QOS-React / commits / eb674e47c8

[Fiber] Add tests for scheduling inside callbacks (#8186)

* Add tests for scheduling inside callbacks * Don't test implementation details

Dan Abramov committed Nov 2, 2016 at 20:11 UTC eb674e47c85e4af20fe07753508eb43a1ac2fb64
3 files changed +397 -101
scripts/fiber/tests-passing.txt
+12
@@ -819,6 +819,18 @@ src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js
819 * splits deferred work on multiple roots
820 * works on deferred roots in the order they were scheduled
821 * handles interleaved deferred and animation work
822 +* performs animation work in animation callback
823 +* schedules deferred work in animation callback
824 +* schedules deferred work and performs animation work in animation callback
825 +* performs animation work and schedules deferred work in animation callback
826 +* performs deferred work in deferred callback if it has time
827 +* schedules deferred work in deferred callback if it runs out of time
828 +* performs animated work in deferred callback if it has time
829 +* performs animated work and deferred work in deferred callback if it has time
830 +* performs deferred and animated work work in deferred callback if it has time
831 +* FIXME: schedules animated work as if it was deferred in deferred callback if it runs out of time
832 +* schedules animated work and deferred work in deferred callback if it runs out of time
833 +* schedules deferred work and animated work in deferred callback if it runs out of time
834
835 src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js
836 * can update child nodes of a host instance
src/renderers/noop/ReactNoop.js
-8
@@ -172,14 +172,6 @@ var ReactNoop = {
172 }
173 },
174
175 - hasScheduledDeferredCallback() {
176 - return Boolean(scheduledDeferredCallback);
177 - },
178 -
179 - hasScheduledAnimationCallback() {
180 - return Boolean(scheduledAnimationCallback);
181 - },
182 -
175 // Shortcut for testing a single root
176 render(element : ReactElement<any>, callback: ?Function) {
177 ReactNoop.renderToRootWithID(element, DEFAULT_ROOT_ID, callback);
src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js
+385 -93
@@ -29,13 +29,9 @@ describe('ReactIncrementalScheduling', () => {
29 ReactNoop.performAnimationWork(() => {
30 ReactNoop.render(<span prop="1" />);
31 });
32 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
33 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
32 expect(ReactNoop.getChildren()).toEqual([]);
33
34 ReactNoop.flushAnimationPri();
37 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
38 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
35 expect(ReactNoop.getChildren()).toEqual([span('1')]);
36 });
37
@@ -45,15 +41,11 @@ describe('ReactIncrementalScheduling', () => {
41 ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
42 ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
43 });
48 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
49 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
44 expect(ReactNoop.getChildren('a')).toEqual([]);
45 expect(ReactNoop.getChildren('b')).toEqual([]);
46 expect(ReactNoop.getChildren('c')).toEqual([]);
47
48 ReactNoop.flushAnimationPri();
55 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
56 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
49 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
50 expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
51 expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
@@ -66,13 +58,9 @@ describe('ReactIncrementalScheduling', () => {
58 ReactNoop.performAnimationWork(() => {
59 ReactNoop.render(<span prop="2" />);
60 });
69 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
70 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
61 expect(ReactNoop.getChildren()).toEqual([]);
62
63 ReactNoop.flushAnimationPri();
74 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
75 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
64 expect(ReactNoop.getChildren()).toEqual([span('2')]);
65 });
66
@@ -87,15 +75,11 @@ describe('ReactIncrementalScheduling', () => {
75 ReactNoop.renderToRootWithID(<span prop="b:2" />, 'b');
76 ReactNoop.renderToRootWithID(<span prop="c:2" />, 'c');
77 });
90 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
91 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
78 expect(ReactNoop.getChildren('a')).toEqual([]);
79 expect(ReactNoop.getChildren('b')).toEqual([]);
80 expect(ReactNoop.getChildren('c')).toEqual([]);
81
82 ReactNoop.flushAnimationPri();
97 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
98 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
83 expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]);
84 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
85 expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]);
@@ -103,13 +87,9 @@ describe('ReactIncrementalScheduling', () => {
87
88 it('schedules and flushes deferred work', () => {
89 ReactNoop.render(<span prop="1" />);
106 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
107 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
90 expect(ReactNoop.getChildren()).toEqual([]);
91
92 ReactNoop.flushDeferredPri();
111 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
112 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
93 expect(ReactNoop.getChildren()).toEqual([span('1')]);
94 });
95
@@ -117,15 +97,11 @@ describe('ReactIncrementalScheduling', () => {
97 ReactNoop.renderToRootWithID(<span prop="a:1" />, 'a');
98 ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
99 ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
120 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
121 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
100 expect(ReactNoop.getChildren('a')).toEqual([]);
101 expect(ReactNoop.getChildren('b')).toEqual([]);
102 expect(ReactNoop.getChildren('c')).toEqual([]);
103
104 ReactNoop.flushDeferredPri();
127 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
128 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
105 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
106 expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
107 expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
@@ -134,13 +110,9 @@ describe('ReactIncrementalScheduling', () => {
110 it('flushes scheduled deferred work fitting within deadline', () => {
111 ReactNoop.render(<span prop="1" />);
112 ReactNoop.render(<span prop="2" />);
137 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
138 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
113 expect(ReactNoop.getChildren()).toEqual([]);
114
115 ReactNoop.flushDeferredPri();
142 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
143 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
116 expect(ReactNoop.getChildren()).toEqual([span('2')]);
117 });
118
@@ -151,15 +123,11 @@ describe('ReactIncrementalScheduling', () => {
123 ReactNoop.renderToRootWithID(<span prop="b:2" />, 'b');
124 ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
125 ReactNoop.renderToRootWithID(<span prop="c:2" />, 'c');
154 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
155 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
126 expect(ReactNoop.getChildren('a')).toEqual([]);
127 expect(ReactNoop.getChildren('b')).toEqual([]);
128 expect(ReactNoop.getChildren('c')).toEqual([]);
129
130 ReactNoop.flushDeferredPri();
161 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
162 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
131 expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]);
132 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
133 expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]);
@@ -168,23 +136,15 @@ describe('ReactIncrementalScheduling', () => {
136 it('schedules more deferred work if it runs out of time', () => {
137 ReactNoop.render(<span prop="1" />);
138 ReactNoop.render(<span prop="2" />);
171 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
172 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
139 expect(ReactNoop.getChildren()).toEqual([]);
140
141 ReactNoop.flushDeferredPri(5);
176 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
177 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
142 expect(ReactNoop.getChildren()).toEqual([]);
143
144 ReactNoop.flushDeferredPri(10);
181 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
182 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
145 expect(ReactNoop.getChildren()).toEqual([]);
146
147 ReactNoop.flushDeferredPri(10);
186 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
187 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
148 expect(ReactNoop.getChildren()).toEqual([span('2')]);
149 });
150
@@ -195,29 +155,21 @@ describe('ReactIncrementalScheduling', () => {
155 ReactNoop.renderToRootWithID(<span prop="b:2" />, 'b');
156 ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
157 ReactNoop.renderToRootWithID(<span prop="c:2" />, 'c');
198 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
199 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
158 expect(ReactNoop.getChildren('a')).toEqual([]);
159 expect(ReactNoop.getChildren('b')).toEqual([]);
160 expect(ReactNoop.getChildren('c')).toEqual([]);
161
162 ReactNoop.flushDeferredPri(15);
205 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
206 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
163 expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]);
164 expect(ReactNoop.getChildren('b')).toEqual([]);
165 expect(ReactNoop.getChildren('c')).toEqual([]);
166
167 ReactNoop.flushDeferredPri(15);
212 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
213 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
168 expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]);
169 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
170 expect(ReactNoop.getChildren('c')).toEqual([]);
171
172 ReactNoop.flushDeferredPri(15);
219 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
220 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
173 expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]);
174 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
175 expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]);
@@ -233,8 +185,6 @@ describe('ReactIncrementalScheduling', () => {
185
186 // FIXME: I would expect true here because we should have scheduled an animation callback:
187 // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
236 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
237 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
188 expect(ReactNoop.getChildren()).toEqual([]);
189
190 // We only scheduled deferred callback so that's what we get.
@@ -242,8 +192,6 @@ describe('ReactIncrementalScheduling', () => {
192 ReactNoop.flushDeferredPri();
193 // TODO: I would expect true here because we should have tried to schedule animation sooner:
194 // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
245 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
246 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
195 expect(ReactNoop.getChildren()).toEqual([span('2')]);
196 });
197
@@ -259,8 +207,6 @@ describe('ReactIncrementalScheduling', () => {
207
208 // FIXME: I would expect true here because we should have scheduled an animation callback:
209 // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
262 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
263 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
210 expect(ReactNoop.getChildren('a')).toEqual([]);
211 expect(ReactNoop.getChildren('b')).toEqual([]);
212 expect(ReactNoop.getChildren('c')).toEqual([]);
@@ -270,8 +216,6 @@ describe('ReactIncrementalScheduling', () => {
216 ReactNoop.flushDeferredPri();
217 // TODO: I would expect true here because we tried to schedule animation sooner, and so it would still be scheduled:
218 // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
273 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
274 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
219 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
220 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
221 expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]);
@@ -289,24 +233,18 @@ describe('ReactIncrementalScheduling', () => {
233
234 // FIXME: I would expect true here because we should have scheduled an animation callback:
235 // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
292 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
293 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
236 expect(ReactNoop.getChildren()).toEqual([]);
237
238 // Flushing animation should have flushed the animation.
239 // FIXME: But it currently doesn't.
240 // Technically we didn't schedule this callback. This test is valid because we should have scheduled it.
241 ReactNoop.flushAnimationPri();
300 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
301 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
242 // TODO: I would expect [span('2')] here because it was scheduled as animation:
243 // expect(ReactNoop.getChildren()).toEqual([span('2')]);
244 expect(ReactNoop.getChildren()).toEqual([]);
245
246 // TODO: I wouldn't expect this flush to be necessary for animation work to kick in.
247 ReactNoop.flushDeferredPri();
308 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
309 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
248 expect(ReactNoop.getChildren()).toEqual([span('2')]);
249 });
250
@@ -324,8 +262,6 @@ describe('ReactIncrementalScheduling', () => {
262
263 // FIXME: I would expect true here because we should have scheduled an animation callback:
264 // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
327 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
328 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
265 expect(ReactNoop.getChildren('a')).toEqual([]);
266 expect(ReactNoop.getChildren('b')).toEqual([]);
267 expect(ReactNoop.getChildren('c')).toEqual([]);
@@ -334,8 +270,6 @@ describe('ReactIncrementalScheduling', () => {
270 // FIXME: But it currently doesn't.
271 // Technically we didn't schedule this callback. This test is valid because we should have scheduled it.
272 ReactNoop.flushAnimationPri();
337 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
338 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
273 // TODO: I would expect this here because they were scheduled as animation:
274 // expect(ReactNoop.getChildren('a')).toEqual([]);
275 // expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
@@ -346,8 +280,6 @@ describe('ReactIncrementalScheduling', () => {
280
281 // TODO: I wouldn't expect this flush to be necessary for animation work to kick in.
282 ReactNoop.flushDeferredPri();
349 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
350 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
283 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
284 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
285 expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]);
@@ -362,10 +294,7 @@ describe('ReactIncrementalScheduling', () => {
294 });
295 // Schedule late deferred
296 ReactNoop.render(<span prop="2" />);
365 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
297 // We could also make this true because we know we have a deferred update coming.
367 - // expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
368 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
298 expect(ReactNoop.getChildren()).toEqual([]);
299
300 // Flushing deferred should have flushed both early animation and late deferred work that invalidated it.
@@ -373,16 +302,12 @@ describe('ReactIncrementalScheduling', () => {
302 // FIXME: Instead, it currently doesn't do anything.
303 // TODO: is this even a valid test? Technically we didn't schedule this callback.
304 ReactNoop.flushDeferredPri();
376 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
377 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
305 // TODO: I would expect [span('2')] here because we should have flushed everything by now:
306 // expect(ReactNoop.getChildren()).toEqual([span('2')]);
307 expect(ReactNoop.getChildren()).toEqual([]);
308
309 // Flushing animation should have been a no-op
310 ReactNoop.flushAnimationPri();
384 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
385 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
311 expect(ReactNoop.getChildren()).toEqual([span('2')]);
312 });
313
@@ -397,10 +322,7 @@ describe('ReactIncrementalScheduling', () => {
322 // Schedule late deferred
323 ReactNoop.renderToRootWithID(<span prop="b:2" />, 'b');
324 ReactNoop.renderToRootWithID(<span prop="c:2" />, 'c');
400 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
325 // We could also make this true because we know we have a deferred update coming.
402 - // expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
403 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
326 expect(ReactNoop.getChildren('a')).toEqual([]);
327 expect(ReactNoop.getChildren('b')).toEqual([]);
328 expect(ReactNoop.getChildren('c')).toEqual([]);
@@ -410,8 +332,6 @@ describe('ReactIncrementalScheduling', () => {
332 // FIXME: Instead, it currently doesn't do anything.
333 // TODO: is this even a valid test? Technically we didn't schedule this callback.
334 ReactNoop.flushDeferredPri();
413 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
414 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
335 // TODO: I would expect this here because we should have flushed everything:
336 // expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
337 // expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
@@ -422,10 +342,8 @@ describe('ReactIncrementalScheduling', () => {
342
343 // Flushing animation should have been a no-op.
344 ReactNoop.flushAnimationPri();
425 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
345 // FIXME: this deferred work should have been handled earlier.
346 // expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
428 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
347 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
348 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
349 // FIXME: this deferred work should have been handled earlier.
@@ -444,15 +362,11 @@ describe('ReactIncrementalScheduling', () => {
362 });
363 // Schedule late deferred
364 ReactNoop.render(<span prop="2" />);
447 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
365 // We don't need a deferred callback because the root already has animation work
449 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
366 expect(ReactNoop.getChildren()).toEqual([]);
367
368 // Flushing animation work flushes everything on this root.
369 ReactNoop.flushAnimationPri();
454 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
455 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
370 expect(ReactNoop.getChildren()).toEqual([span('2')]);
371 });
372
@@ -465,27 +379,20 @@ describe('ReactIncrementalScheduling', () => {
379 // Schedule late deferred
380 ReactNoop.renderToRootWithID(<span prop="b:2" />, 'b');
381 ReactNoop.renderToRootWithID(<span prop="c:2" />, 'c');
468 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
382 // TODO: I would expect this to be true because we know we have a deferred update coming.
470 - // expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
471 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
383 expect(ReactNoop.getChildren('a')).toEqual([]);
384 expect(ReactNoop.getChildren('b')).toEqual([]);
385 expect(ReactNoop.getChildren('c')).toEqual([]);
386
387 // Flushing animation work flushes all roots with animation work.
388 ReactNoop.flushAnimationPri();
478 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
389 // Now we know we also need a deferred update. Should we have scheduled it earlier?
480 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(true);
390 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
391 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
392 expect(ReactNoop.getChildren('c')).toEqual([]);
393
394 // Flushing deferred work flushes the root with only deferred work.
395 ReactNoop.flushDeferredPri();
487 - expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
488 - expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
396 expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
397 expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);
398 expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]);
@@ -614,4 +521,389 @@ describe('ReactIncrementalScheduling', () => {
521 expect(ReactNoop.getChildren('b')).toEqual([span('b:3')]);
522 expect(ReactNoop.getChildren('c')).toEqual([span('c:3')]);
523 });
524 +
525 + it('performs animation work in animation callback', () => {
526 + class Foo extends React.Component {
527 + componentDidMount() {
528 + // Animation work that will get performed during animation callback
529 + ReactNoop.performAnimationWork(() => {
530 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
531 + });
532 + }
533 + render() {
534 + return <span prop="a:1" />;
535 + }
536 + }
537 +
538 + // Schedule animation work
539 + ReactNoop.performAnimationWork(() => {
540 + ReactNoop.renderToRootWithID(<Foo />, 'a');
541 + });
542 +
543 + // Flushing animation work should flush animation work scheduled inside it
544 + ReactNoop.flushAnimationPri();
545 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
546 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
547 + });
548 +
549 + it('schedules deferred work in animation callback', () => {
550 + class Foo extends React.Component {
551 + componentDidMount() {
552 + // Deferred work that will get scheduled during animation callback
553 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
554 + }
555 + render() {
556 + return <span prop="a:1" />;
557 + }
558 + }
559 +
560 + // Schedule animation work
561 + ReactNoop.performAnimationWork(() => {
562 + ReactNoop.renderToRootWithID(<Foo />, 'a');
563 + });
564 +
565 + // Flushing animation work should not flush the deferred work
566 + ReactNoop.flushAnimationPri();
567 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
568 + expect(ReactNoop.getChildren('b')).toEqual([]);
569 +
570 + // Flush the deferred work
571 + ReactNoop.flushDeferredPri();
572 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
573 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
574 + });
575 +
576 + it('schedules deferred work and performs animation work in animation callback', () => {
577 + let hasScheduled = false;
578 + class Foo extends React.Component {
579 + componentDidMount() {
580 + // Deferred work that will get scheduled during animation callback
581 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
582 + // Animation work that will get performed during animation callback
583 + ReactNoop.performAnimationWork(() => {
584 + ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
585 + });
586 + // Deferred work that will get scheduled during animation callback
587 + ReactNoop.renderToRootWithID(<span prop="d:1" />, 'd');
588 + hasScheduled = true;
589 + }
590 + render() {
591 + return <span prop="a:1" />;
592 + }
593 + }
594 +
595 + // Schedule animation work
596 + ReactNoop.performAnimationWork(() => {
597 + ReactNoop.renderToRootWithID(<Foo />, 'a');
598 + });
599 +
600 + // Flushing animation work should flush animation work scheduled inside it
601 + ReactNoop.flushAnimationPri();
602 + expect(hasScheduled).toBe(true);
603 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
604 + expect(ReactNoop.getChildren('b')).toEqual([]);
605 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
606 + expect(ReactNoop.getChildren('d')).toEqual([]);
607 +
608 + // Flush the deferred work
609 + ReactNoop.flushDeferredPri();
610 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
611 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
612 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
613 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
614 + });
615 +
616 + it('performs animation work and schedules deferred work in animation callback', () => {
617 + let hasScheduled = false;
618 + class Foo extends React.Component {
619 + componentDidMount() {
620 + // Animation work that will get performed during animation callback
621 + ReactNoop.performAnimationWork(() => {
622 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
623 + });
624 + // Deferred work that will get scheduled during animation callback
625 + ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
626 + // Animation work that will get performed during animation callback
627 + ReactNoop.performAnimationWork(() => {
628 + ReactNoop.renderToRootWithID(<span prop="d:1" />, 'd');
629 + });
630 + hasScheduled = true;
631 + }
632 + render() {
633 + return <span prop="a:1" />;
634 + }
635 + }
636 +
637 + // Schedule animation work
638 + ReactNoop.performAnimationWork(() => {
639 + ReactNoop.renderToRootWithID(<Foo />, 'a');
640 + });
641 +
642 + // Flushing animation work should flush animation work scheduled inside it
643 + ReactNoop.flushAnimationPri();
644 + expect(hasScheduled).toBe(true);
645 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
646 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
647 + expect(ReactNoop.getChildren('c')).toEqual([]);
648 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
649 +
650 + // Flush the deferred work
651 + ReactNoop.flushDeferredPri();
652 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
653 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
654 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
655 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
656 + });
657 +
658 + it('performs deferred work in deferred callback if it has time', () => {
659 + class Foo extends React.Component {
660 + componentDidMount() {
661 + // Deferred work that will get performed during deferred callback
662 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
663 + }
664 + render() {
665 + return <span prop="a:1" />;
666 + }
667 + }
668 +
669 + // Schedule deferred work
670 + ReactNoop.renderToRootWithID(<Foo />, 'a');
671 +
672 + // Flushing deferred work should flush deferred work scheduled inside it
673 + ReactNoop.flushDeferredPri();
674 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
675 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
676 + });
677 +
678 + it('schedules deferred work in deferred callback if it runs out of time', () => {
679 + let hasScheduled = false;
680 + class Foo extends React.Component {
681 + componentDidMount() {
682 + // Deferred work that will get scheduled during deferred callback
683 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
684 + hasScheduled = true;
685 + }
686 + render() {
687 + return <span prop="a:1" />;
688 + }
689 + }
690 +
691 + // Schedule deferred work
692 + ReactNoop.renderToRootWithID(<Foo />, 'a');
693 +
694 + // Flush just enough deferred work to schedule more deferred work
695 + ReactNoop.flushDeferredPri(20);
696 + expect(hasScheduled).toBe(true);
697 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
698 + expect(ReactNoop.getChildren('b')).toEqual([]);
699 +
700 + // Flush the rest of the deferred work
701 + ReactNoop.flushDeferredPri(15);
702 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
703 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
704 + });
705 +
706 + it('performs animated work in deferred callback if it has time', () => {
707 + class Foo extends React.Component {
708 + componentDidMount() {
709 + // Animated work that will get performed during deferred callback
710 + ReactNoop.performAnimationWork(() => {
711 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
712 + });
713 + }
714 + render() {
715 + return <span prop="a:1" />;
716 + }
717 + }
718 +
719 + // Schedule deferred work
720 + ReactNoop.renderToRootWithID(<Foo />, 'a');
721 +
722 + // Flushing deferred work should flush animated work scheduled inside it
723 + ReactNoop.flushDeferredPri();
724 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
725 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
726 + });
727 +
728 + it('performs animated work and deferred work in deferred callback if it has time', () => {
729 + class Foo extends React.Component {
730 + componentDidMount() {
731 + // Deferred work that will get performed during deferred callback
732 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
733 + // Animation work that will get performed during deferred callback
734 + ReactNoop.performAnimationWork(() => {
735 + ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
736 + });
737 + // Deferred work that will get performed during deferred callback
738 + ReactNoop.renderToRootWithID(<span prop="d:1" />, 'd');
739 + }
740 + render() {
741 + return <span prop="a:1" />;
742 + }
743 + }
744 +
745 + // Schedule deferred work
746 + ReactNoop.renderToRootWithID(<Foo />, 'a');
747 +
748 + // Flushing deferred work should flush both deferred and animated work scheduled inside it
749 + ReactNoop.flushDeferredPri();
750 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
751 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
752 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
753 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
754 + });
755 +
756 + it('performs deferred and animated work work in deferred callback if it has time', () => {
757 + class Foo extends React.Component {
758 + componentDidMount() {
759 + // Animation work that will get performed during deferred callback
760 + ReactNoop.performAnimationWork(() => {
761 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
762 + });
763 + // Deferred work that will get performed during deferred callback
764 + ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
765 + // Animation work that will get performed during deferred callback
766 + ReactNoop.performAnimationWork(() => {
767 + ReactNoop.renderToRootWithID(<span prop="d:1" />, 'd');
768 + });
769 + }
770 + render() {
771 + return <span prop="a:1" />;
772 + }
773 + }
774 +
775 + // Schedule deferred work
776 + ReactNoop.renderToRootWithID(<Foo />, 'a');
777 +
778 + // Flushing deferred work should flush both deferred and animated work scheduled inside it
779 + ReactNoop.flushDeferredPri();
780 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
781 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
782 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
783 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
784 + });
785 +
786 + // This test documents the existing behavior. Desired behavior:
787 + // it('schedules animated work in deferred callback if it runs out of time', () => {
788 + it('FIXME: schedules animated work as if it was deferred in deferred callback if it runs out of time', () => {
789 + let hasScheduled = false;
790 + class Foo extends React.Component {
791 + componentDidMount() {
792 + // Animated work that will get scheduled during deferred callback
793 + ReactNoop.performAnimationWork(() => {
794 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
795 + });
796 + hasScheduled = true;
797 + }
798 + render() {
799 + return <span prop="a:1" />;
800 + }
801 + }
802 +
803 + // Schedule deferred work
804 + ReactNoop.renderToRootWithID(<Foo />, 'a');
805 +
806 + // Flush just enough deferred work to schedule animated work
807 + ReactNoop.flushDeferredPri(20);
808 + expect(hasScheduled).toBe(true);
809 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
810 + expect(ReactNoop.getChildren('b')).toEqual([]);
811 + // FIXME: I would expect these to be flipped because animation work was scheduled.
812 + // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(true);
813 + // expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
814 +
815 + // Flush the rest of work in an animated callback.
816 + // Technically we didn't schedule this callback. This test is valid because we should have scheduled it.
817 + ReactNoop.flushAnimationPri();
818 + // FIXME: we should have flushed everything here.
819 + // expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
820 + // expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
821 + // expect(ReactNoop.hasScheduledAnimationCallback()).toBe(false);
822 + // expect(ReactNoop.hasScheduledDeferredCallback()).toBe(false);
823 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
824 + expect(ReactNoop.getChildren('b')).toEqual([]);
825 +
826 + // FIXME: it should be unnecessary to flush the deferred work:
827 + ReactNoop.flushDeferredPri();
828 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
829 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
830 + });
831 +
832 + it('schedules animated work and deferred work in deferred callback if it runs out of time', () => {
833 + let isScheduled = false;
834 + class Foo extends React.Component {
835 + componentDidMount() {
836 + // Deferred work that will get performed during deferred callback
837 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
838 + // Animation work that will get performed during deferred callback
839 + ReactNoop.performAnimationWork(() => {
840 + ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
841 + });
842 + // Deferred work that will get performed during deferred callback
843 + ReactNoop.renderToRootWithID(<span prop="d:1" />, 'd');
844 + isScheduled = true;
845 + }
846 + render() {
847 + return <span prop="a:1" />;
848 + }
849 + }
850 +
851 + // Schedule deferred work
852 + ReactNoop.renderToRootWithID(<Foo />, 'a');
853 +
854 + // Flushing deferred work should schedule both deferred and animated work
855 + ReactNoop.flushDeferredPri(20);
856 + expect(isScheduled).toBe(true);
857 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
858 + expect(ReactNoop.getChildren('b')).toEqual([]);
859 + expect(ReactNoop.getChildren('c')).toEqual([]);
860 + expect(ReactNoop.getChildren('d')).toEqual([]);
861 +
862 + // Flush the rest of the work
863 + ReactNoop.flushDeferredPri();
864 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
865 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
866 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
867 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
868 + });
869 +
870 + it('schedules deferred work and animated work in deferred callback if it runs out of time', () => {
871 + let isScheduled = false;
872 + class Foo extends React.Component {
873 + componentDidMount() {
874 + // Animation work that will get performed during deferred callback
875 + ReactNoop.performAnimationWork(() => {
876 + ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');
877 + });
878 + // Deferred work that will get performed during deferred callback
879 + ReactNoop.renderToRootWithID(<span prop="c:1" />, 'c');
880 + // Animation work that will get performed during deferred callback
881 + ReactNoop.performAnimationWork(() => {
882 + ReactNoop.renderToRootWithID(<span prop="d:1" />, 'd');
883 + });
884 + isScheduled = true;
885 + }
886 + render() {
887 + return <span prop="a:1" />;
888 + }
889 + }
890 +
891 + // Schedule deferred work
892 + ReactNoop.renderToRootWithID(<Foo />, 'a');
893 +
894 + // Flushing deferred work should schedule both deferred and animated work
895 + ReactNoop.flushDeferredPri(20);
896 + expect(isScheduled).toBe(true);
897 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
898 + expect(ReactNoop.getChildren('b')).toEqual([]);
899 + expect(ReactNoop.getChildren('c')).toEqual([]);
900 + expect(ReactNoop.getChildren('d')).toEqual([]);
901 +
902 + // Flush the rest of the work
903 + ReactNoop.flushDeferredPri();
904 + expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]);
905 + expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);
906 + expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]);
907 + expect(ReactNoop.getChildren('d')).toEqual([span('d:1')]);
908 + });
909 });