@samitouri / QOS-React / commits / 1f32d3c6dc

Test renderer flushAll method verifies an array of expected yields (#13174)

Brian Vaughn committed Jul 9, 2018 at 09:05 UTC 1f32d3c6dcc51f6a540997ab884a300b3f2ac5d4
3 files changed +89 -55
packages/react-test-renderer/src/ReactTestRendererScheduling.js
+39 -36
@@ -12,7 +12,7 @@ import type {Deadline} from 'react-reconciler/src/ReactFiberScheduler';
12 // Current virtual time
13 export let nowImplementation = () => 0;
14 export let scheduledCallback: ((deadline: Deadline) => mixed) | null = null;
15 -export let yieldedValues: Array<mixed> | null = null;
15 +export let yieldedValues: Array<mixed> = [];
16
17 export function scheduleDeferredCallback(
18 callback: (deadline: Deadline) => mixed,
@@ -31,8 +31,39 @@ export function setNowImplementation(implementation: () => number): void {
31 nowImplementation = implementation;
32 }
33
34 -export function flushAll(): Array<mixed> {
35 - yieldedValues = null;
34 +function verifyExpectedValues(expectedValues: Array<mixed>): void {
35 + for (let i = 0; i < expectedValues.length; i++) {
36 + const expectedValue = `"${(expectedValues[i]: any)}"`;
37 + const yieldedValue =
38 + i < yieldedValues.length ? `"${(yieldedValues[i]: any)}"` : 'nothing';
39 + if (yieldedValue !== expectedValue) {
40 + const error = new Error(
41 + `Flush expected to yield ${(expectedValue: any)}, but ${(yieldedValue: any)} was yielded`,
42 + );
43 + // Attach expected and yielded arrays,
44 + // So the caller could pretty print the diff (if desired).
45 + (error: any).expectedValues = expectedValues;
46 + (error: any).actualValues = yieldedValues;
47 + throw error;
48 + }
49 + }
50 +
51 + if (expectedValues.length !== yieldedValues.length) {
52 + const error = new Error(
53 + `Flush expected to yield ${expectedValues.length} values, but yielded ${
54 + yieldedValues.length
55 + }`,
56 + );
57 + // Attach expected and yielded arrays,
58 + // So the caller could pretty print the diff (if desired).
59 + (error: any).expectedValues = expectedValues;
60 + (error: any).actualValues = yieldedValues;
61 + throw error;
62 + }
63 +}
64 +
65 +export function flushAll(expectedValues: Array<mixed>): Array<mixed> {
66 + yieldedValues = [];
67 while (scheduledCallback !== null) {
68 const cb = scheduledCallback;
69 scheduledCallback = null;
@@ -47,25 +78,19 @@ export function flushAll(): Array<mixed> {
78 didTimeout: false,
79 });
80 }
50 - if (yieldedValues === null) {
51 - // Always return an array.
52 - return [];
53 - }
81 + verifyExpectedValues(expectedValues);
82 return yieldedValues;
83 }
84
85 export function flushThrough(expectedValues: Array<mixed>): Array<mixed> {
86 let didStop = false;
59 - yieldedValues = null;
87 + yieldedValues = [];
88 while (scheduledCallback !== null && !didStop) {
89 const cb = scheduledCallback;
90 scheduledCallback = null;
91 cb({
92 timeRemaining() {
65 - if (
66 - yieldedValues !== null &&
67 - yieldedValues.length >= expectedValues.length
68 - ) {
93 + if (yieldedValues.length >= expectedValues.length) {
94 // We at least as many values as expected. Stop rendering.
95 didStop = true;
96 return 0;
@@ -79,34 +104,12 @@ export function flushThrough(expectedValues: Array<mixed>): Array<mixed> {
104 didTimeout: false,
105 });
106 }
82 - if (yieldedValues === null) {
83 - // Always return an array.
84 - yieldedValues = [];
85 - }
86 - for (let i = 0; i < expectedValues.length; i++) {
87 - const expectedValue = `"${(expectedValues[i]: any)}"`;
88 - const yieldedValue =
89 - i < yieldedValues.length ? `"${(yieldedValues[i]: any)}"` : 'nothing';
90 - if (yieldedValue !== expectedValue) {
91 - const error = new Error(
92 - `flushThrough expected to yield ${(expectedValue: any)}, but ${(yieldedValue: any)} was yielded`,
93 - );
94 - // Attach expected and yielded arrays,
95 - // So the caller could pretty print the diff (if desired).
96 - (error: any).expectedValues = expectedValues;
97 - (error: any).actualValues = yieldedValues;
98 - throw error;
99 - }
100 - }
107 + verifyExpectedValues(expectedValues);
108 return yieldedValues;
109 }
110
111 export function yieldValue(value: mixed): void {
105 - if (yieldedValues === null) {
106 - yieldedValues = [value];
107 - } else {
108 - yieldedValues.push(value);
109 - }
112 + yieldedValues.push(value);
113 }
114
115 export function withCleanYields(fn: Function) {
packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.js
+42 -8
@@ -32,7 +32,7 @@ describe('ReactTestRendererAsync', () => {
32 expect(renderer.toJSON()).toEqual(null);
33
34 // Flush initial mount.
35 - renderer.unstable_flushAll();
35 + renderer.unstable_flushAll([]);
36 expect(renderer.toJSON()).toEqual('Hi');
37
38 // Update
@@ -40,7 +40,7 @@ describe('ReactTestRendererAsync', () => {
40 // Not yet updated.
41 expect(renderer.toJSON()).toEqual('Hi');
42 // Flush update.
43 - renderer.unstable_flushAll();
43 + renderer.unstable_flushAll([]);
44 expect(renderer.toJSON()).toEqual('Bye');
45 });
46
@@ -62,11 +62,11 @@ describe('ReactTestRendererAsync', () => {
62 unstable_isAsync: true,
63 });
64
65 - expect(renderer.unstable_flushAll()).toEqual(['A:1', 'B:1', 'C:1']);
65 + renderer.unstable_flushAll(['A:1', 'B:1', 'C:1']);
66 expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
67
68 renderer.update(<Parent step={2} />);
69 - expect(renderer.unstable_flushAll()).toEqual(['A:2', 'B:2', 'C:2']);
69 + renderer.unstable_flushAll(['A:2', 'B:2', 'C:2']);
70 expect(renderer.toJSON()).toEqual(['A:2', 'B:2', 'C:2']);
71 });
72
@@ -97,7 +97,7 @@ describe('ReactTestRendererAsync', () => {
97 expect(renderer.toJSON()).toEqual(null);
98
99 // Flush the remaining work
100 - expect(renderer.unstable_flushAll()).toEqual(['C:1']);
100 + renderer.unstable_flushAll(['C:1']);
101 expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
102 });
103
@@ -159,7 +159,41 @@ describe('ReactTestRendererAsync', () => {
159 );
160
161 expect(() => renderer.unstable_flushThrough(['foo', 'baz'])).toThrow(
162 - 'flushThrough expected to yield "baz", but "bar" was yielded',
162 + 'Flush expected to yield "baz", but "bar" was yielded',
163 + );
164 + });
165 +
166 + it('should error if flushAll params dont match yielded values', () => {
167 + const Yield = ({id}) => {
168 + renderer.unstable_yield(id);
169 + return id;
170 + };
171 +
172 + const renderer = ReactTestRenderer.create(
173 + <div>
174 + <Yield id="foo" />
175 + <Yield id="bar" />
176 + <Yield id="baz" />
177 + </div>,
178 + {
179 + unstable_isAsync: true,
180 + },
181 + );
182 +
183 + expect(() => renderer.unstable_flushAll([])).toThrow(
184 + 'Flush expected to yield 0 values, but yielded 3',
185 + );
186 +
187 + renderer.update(
188 + <div>
189 + <Yield id="foo" />
190 + <Yield id="bar" />
191 + <Yield id="baz" />
192 + </div>,
193 + );
194 +
195 + expect(() => renderer.unstable_flushAll(['foo', 'baz'])).toThrow(
196 + 'Flush expected to yield "baz", but "bar" was yielded',
197 );
198 });
199
@@ -179,7 +213,7 @@ describe('ReactTestRendererAsync', () => {
213 );
214
215 expect(() => renderer.unstable_flushThrough(['foo', 'bar'])).toThrow(
182 - 'flushThrough expected to yield "bar", but nothing was yielded',
216 + 'Flush expected to yield "bar", but nothing was yielded',
217 );
218 });
219
@@ -189,7 +223,7 @@ describe('ReactTestRendererAsync', () => {
223 });
224
225 expect(() => renderer.unstable_flushThrough(['foo'])).toThrow(
192 - 'flushThrough expected to yield "foo", but nothing was yielded',
226 + 'Flush expected to yield "foo", but nothing was yielded',
227 );
228 });
229 });
packages/react/src/__tests__/ReactProfiler-test.internal.js
+8 -11
@@ -178,7 +178,7 @@ describe('Profiler', () => {
178 // Times are logged until a render is committed.
179 renderer.unstable_flushThrough(['first']);
180 expect(callback).toHaveBeenCalledTimes(0);
181 - expect(renderer.unstable_flushAll()).toEqual(['last']);
181 + renderer.unstable_flushAll(['last']);
182 expect(callback).toHaveBeenCalledTimes(1);
183 });
184
@@ -532,7 +532,7 @@ describe('Profiler', () => {
532 expect(callback).toHaveBeenCalledTimes(0);
533
534 // Resume render for remaining children.
535 - expect(renderer.unstable_flushAll()).toEqual(['Yield:3']);
535 + renderer.unstable_flushAll(['Yield:3']);
536
537 // Verify that logged times include both durations above.
538 expect(callback).toHaveBeenCalledTimes(1);
@@ -576,7 +576,7 @@ describe('Profiler', () => {
576
577 // Flush the remaninig work,
578 // Which should take an additional 10ms of simulated time.
579 - expect(renderer.unstable_flushAll()).toEqual(['Yield:10', 'Yield:17']);
579 + renderer.unstable_flushAll(['Yield:10', 'Yield:17']);
580 expect(callback).toHaveBeenCalledTimes(2);
581
582 const [innerCall, outerCall] = callback.mock.calls;
@@ -647,7 +647,7 @@ describe('Profiler', () => {
647 callback.mockReset();
648
649 // Verify no more unexpected callbacks from low priority work
650 - expect(renderer.unstable_flushAll()).toEqual([]);
650 + renderer.unstable_flushAll([]);
651 expect(callback).toHaveBeenCalledTimes(0);
652 });
653
@@ -672,7 +672,7 @@ describe('Profiler', () => {
672
673 // Render everything initially.
674 // This should take 21 seconds of actual and base time.
675 - expect(renderer.unstable_flushAll()).toEqual(['Yield:6', 'Yield:15']);
675 + renderer.unstable_flushAll(['Yield:6', 'Yield:15']);
676 expect(callback).toHaveBeenCalledTimes(1);
677 let call = callback.mock.calls[0];
678 expect(call[2]).toBe(21); // actual time
@@ -733,7 +733,7 @@ describe('Profiler', () => {
733 expect(call[5]).toBe(275); // commit time
734
735 // Verify no more unexpected callbacks from low priority work
736 - expect(renderer.unstable_flushAll()).toEqual([]);
736 + renderer.unstable_flushAll([]);
737 expect(callback).toHaveBeenCalledTimes(1);
738 });
739
@@ -780,7 +780,7 @@ describe('Profiler', () => {
780 // Render everything initially.
781 // This simulates a total of 14ms of actual render time.
782 // The base render time is also 14ms for the initial render.
783 - expect(renderer.unstable_flushAll()).toEqual([
783 + renderer.unstable_flushAll([
784 'FirstComponent:1',
785 'Yield:4',
786 'SecondComponent:2',
@@ -836,10 +836,7 @@ describe('Profiler', () => {
836 // The tree contains 42ms of base render time at this point,
837 // Reflecting the most recent (longer) render durations.
838 // TODO: This actual time should decrease by 10ms once the scheduler supports resuming.
839 - expect(renderer.unstable_flushAll()).toEqual([
840 - 'FirstComponent:10',
841 - 'Yield:4',
842 - ]);
839 + renderer.unstable_flushAll(['FirstComponent:10', 'Yield:4']);
840 expect(callback).toHaveBeenCalledTimes(1);
841 call = callback.mock.calls[0];
842 expect(call[2]).toBe(14); // actual time