Adds ReactScheduler red->green unit test for bug fixed in #12834 (#12861)
* Scheduler red->green unit test for bug * fix lint issue * ran prettier
Royi Hagigi committed
May 18, 2018 at 15:05 UTC
c0fe8d6f6942f5cbc93c09825e803ba8cf950522
1 file changed
+51
-11
packages/react-scheduler/src/__tests__/ReactScheduler-test.js
+51
-11
@@ -12,6 +12,20 @@
12
let ReactScheduler;
13
14
describe('ReactScheduler', () => {
15
+ let postMessageCallback;
16
+ let postMessageEvents = [];
17
+
18
+ function drainPostMessageQueue() {
19
+ if (postMessageCallback) {
20
+ while (postMessageEvents.length) {
21
+ postMessageCallback(postMessageEvents.shift());
22
+ }
23
+ }
24
+ }
25
+ function advanceAll() {
26
+ jest.runAllTimers();
27
+ drainPostMessageQueue();
28
+ }
29
beforeEach(() => {
30
// TODO pull this into helper method, reduce repetition.
31
// mock the browser APIs which are used in react-scheduler:
@@ -23,7 +37,8 @@ describe('ReactScheduler', () => {
37
});
38
};
39
const originalAddEventListener = global.addEventListener;
26
- let postMessageCallback;
40
+ postMessageCallback = null;
41
+ postMessageEvents = [];
42
global.addEventListener = function(eventName, callback, useCapture) {
43
if (eventName === 'message') {
44
postMessageCallback = callback;
@@ -33,9 +48,7 @@ describe('ReactScheduler', () => {
48
};
49
global.postMessage = function(messageKey, targetOrigin) {
50
const postMessageEvent = {source: window, data: messageKey};
36
- if (postMessageCallback) {
37
- postMessageCallback(postMessageEvent);
38
- }
51
+ postMessageEvents.push(postMessageEvent);
52
};
53
jest.resetModules();
54
ReactScheduler = require('react-scheduler');
@@ -46,7 +59,7 @@ describe('ReactScheduler', () => {
59
const {scheduleWork} = ReactScheduler;
60
const cb = jest.fn();
61
scheduleWork(cb);
49
- jest.runAllTimers();
62
+ advanceAll();
63
expect(cb.mock.calls.length).toBe(1);
64
// should not have timed out and should include a timeRemaining method
65
expect(cb.mock.calls[0][0].didTimeout).toBe(false);
@@ -66,7 +79,7 @@ describe('ReactScheduler', () => {
79
scheduleWork(callbackB);
80
expect(callbackLog).toEqual([]);
81
// after a delay, calls as many callbacks as it has time for
69
- jest.runAllTimers();
82
+ advanceAll();
83
expect(callbackLog).toEqual(['A', 'B']);
84
// callbackA should not have timed out and should include a timeRemaining method
85
expect(callbackA.mock.calls[0][0].didTimeout).toBe(false);
@@ -80,6 +93,33 @@ describe('ReactScheduler', () => {
93
);
94
});
95
96
+ it("accepts callbacks betweeen animationFrame and postMessage and doesn't stall", () => {
97
+ const {scheduleWork} = ReactScheduler;
98
+ const callbackLog = [];
99
+ const callbackA = jest.fn(() => callbackLog.push('A'));
100
+ const callbackB = jest.fn(() => callbackLog.push('B'));
101
+ const callbackC = jest.fn(() => callbackLog.push('C'));
102
+ scheduleWork(callbackA);
103
+ // initially waits to call the callback
104
+ expect(callbackLog).toEqual([]);
105
+ jest.runAllTimers();
106
+ // this should schedule work *after* the requestAnimationFrame but before the message handler
107
+ scheduleWork(callbackB);
108
+ expect(callbackLog).toEqual([]);
109
+ // now it should drain the message queue and do all scheduled work
110
+ drainPostMessageQueue();
111
+ expect(callbackLog).toEqual(['A', 'B']);
112
+
113
+ // advances timers, now with an empty queue of work (to ensure they don't deadlock)
114
+ advanceAll();
115
+
116
+ // see if more work can be done now.
117
+ scheduleWork(callbackC);
118
+ expect(callbackLog).toEqual(['A', 'B']);
119
+ advanceAll();
120
+ expect(callbackLog).toEqual(['A', 'B', 'C']);
121
+ });
122
+
123
it(
124
'schedules callbacks in correct order and' +
125
'keeps calling them if there is time',
@@ -105,7 +145,7 @@ describe('ReactScheduler', () => {
145
expect(callbackLog).toEqual([]);
146
// after a delay, calls the scheduled callbacks,
147
// and also calls new callbacks scheduled by current callbacks
108
- jest.runAllTimers();
148
+ advanceAll();
149
expect(callbackLog).toEqual(['A', 'B', 'C']);
150
},
151
);
@@ -141,7 +181,7 @@ describe('ReactScheduler', () => {
181
// initially waits to call the callback
182
expect(callbackLog).toEqual([]);
183
// while flushing callbacks, calls as many as it has time for
144
- jest.runAllTimers();
184
+ advanceAll();
185
expect(callbackLog).toEqual(['A', 'B', 'C', 'D', 'E', 'F']);
186
});
187
@@ -164,7 +204,7 @@ describe('ReactScheduler', () => {
204
scheduleWork(callbackB);
205
expect(callbackLog).toEqual([]);
206
// after a delay, calls the latest callback passed
167
- jest.runAllTimers();
207
+ advanceAll();
208
expect(callbackLog).toEqual(['A0', 'B', 'A1']);
209
});
210
});
@@ -177,7 +217,7 @@ describe('ReactScheduler', () => {
217
const callbackId = scheduleWork(cb);
218
expect(cb.mock.calls.length).toBe(0);
219
cancelScheduledWork(callbackId);
180
- jest.runAllTimers();
220
+ advanceAll();
221
expect(cb.mock.calls.length).toBe(0);
222
});
223
@@ -195,7 +235,7 @@ describe('ReactScheduler', () => {
235
callbackBId = scheduleWork(callbackB);
236
// Initially doesn't call anything
237
expect(callbackLog).toEqual([]);
198
- jest.runAllTimers();
238
+ advanceAll();
239
// B should not get called because A cancelled B
240
expect(callbackLog).toEqual(['A']);
241
expect(callbackB.mock.calls.length).toBe(0);