Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[scheduler] 1/n Improve tests for 'schedule' module #12880

Merged
merged 1 commit into from
May 24, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 33 additions & 29 deletions packages/react-scheduler/src/__tests__/ReactScheduler-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,25 @@
'use strict';

let ReactScheduler;
type FrameTimeoutConfigType = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we don't run Flow on tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:( I noticed that. We could either consider it as inline documentation for now, or I can replace it with comments in order to avoid a false sense of security.

// should only specify one or the other
timeLeftInFrame: ?number,
timePastFrameDeadline: ?number,
};

describe('ReactScheduler', () => {
let rAFCallbacks = [];
let postMessageCallback;
let postMessageEvents = [];

function drainPostMessageQueue() {
// default to this falling about 15 ms before next frame
currentTime = startOfLatestFrame + frameSize - 15;
function runPostMessageCallbacks(config: FrameTimeoutConfigType) {
let timeLeftInFrame = 0;
if (typeof config.timeLeftInFrame === 'number') {
timeLeftInFrame = config.timeLeftInFrame;
} else if (typeof config.timePastFrameDeadline === 'number') {
timeLeftInFrame = -1 * config.timePastFrameDeadline;
}
currentTime = startOfLatestFrame + frameSize - timeLeftInFrame;
if (postMessageCallback) {
while (postMessageEvents.length) {
postMessageCallback(postMessageEvents.shift());
Expand All @@ -31,9 +41,9 @@ describe('ReactScheduler', () => {
rAFCallbacks.forEach(cb => cb());
rAFCallbacks = [];
}
function advanceAll() {
function advanceOneFrame(config: FrameTimeoutConfigType = {}) {
runRAFCallbacks();
drainPostMessageQueue();
runPostMessageCallbacks(config);
}

let frameSize = 33;
Expand Down Expand Up @@ -77,7 +87,7 @@ describe('ReactScheduler', () => {
const {scheduleWork} = ReactScheduler;
const cb = jest.fn();
scheduleWork(cb);
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(cb.mock.calls.length).toBe(1);
// should not have timed out and should include a timeRemaining method
expect(cb.mock.calls[0][0].didTimeout).toBe(false);
Expand All @@ -97,7 +107,7 @@ describe('ReactScheduler', () => {
scheduleWork(callbackB);
expect(callbackLog).toEqual([]);
// after a delay, calls as many callbacks as it has time for
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(callbackLog).toEqual(['A', 'B']);
// callbackA should not have timed out and should include a timeRemaining method
expect(callbackA.mock.calls[0][0].didTimeout).toBe(false);
Expand Down Expand Up @@ -125,16 +135,16 @@ describe('ReactScheduler', () => {
scheduleWork(callbackB);
expect(callbackLog).toEqual([]);
// now it should drain the message queue and do all scheduled work
drainPostMessageQueue();
runPostMessageCallbacks({timeLeftInFrame: 15});
expect(callbackLog).toEqual(['A', 'B']);

// advances timers, now with an empty queue of work (to ensure they don't deadlock)
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});

// see if more work can be done now.
scheduleWork(callbackC);
expect(callbackLog).toEqual(['A', 'B']);
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(callbackLog).toEqual(['A', 'B', 'C']);
});

Expand Down Expand Up @@ -163,7 +173,7 @@ describe('ReactScheduler', () => {
expect(callbackLog).toEqual([]);
// after a delay, calls the scheduled callbacks,
// and also calls new callbacks scheduled by current callbacks
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(callbackLog).toEqual(['A', 'B', 'C']);
},
);
Expand Down Expand Up @@ -199,7 +209,7 @@ describe('ReactScheduler', () => {
// initially waits to call the callback
expect(callbackLog).toEqual([]);
// while flushing callbacks, calls as many as it has time for
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(callbackLog).toEqual(['A', 'B', 'C', 'D', 'E', 'F']);
});

Expand All @@ -222,7 +232,7 @@ describe('ReactScheduler', () => {
scheduleWork(callbackB);
expect(callbackLog).toEqual([]);
// after a delay, calls the latest callback passed
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(callbackLog).toEqual(['A0', 'B', 'A1']);
});
});
Expand All @@ -248,24 +258,20 @@ describe('ReactScheduler', () => {
scheduleWork(callbackB, {timeout: 100}); // times out later
scheduleWork(callbackC, {timeout: 2}); // will time out fast

runRAFCallbacks(); // runs rAF callback
// push time ahead a bit so that we have no idle time
startOfLatestFrame += 16;
drainPostMessageQueue(); // runs postMessage callback, idleTick
advanceOneFrame({timePastFrameDeadline: 16});

// callbackC should have timed out
expect(callbackLog).toEqual(['C']);

runRAFCallbacks(); // runs rAF callback
// push time ahead a bit so that we have no idle time
startOfLatestFrame += 16;
drainPostMessageQueue(); // runs postMessage callback, idleTick
advanceOneFrame({timePastFrameDeadline: 16});

// callbackB should have timed out
expect(callbackLog).toEqual(['C', 'B']);

runRAFCallbacks(); // runs rAF callback
drainPostMessageQueue(); // runs postMessage callback, idleTick
// let's give ourselves some idle time now
advanceOneFrame({timeLeftInFrame: 16});

// we should have run callbackA in the idle time
expect(callbackLog).toEqual(['C', 'B', 'A']);
Expand Down Expand Up @@ -295,27 +301,25 @@ describe('ReactScheduler', () => {
scheduleWork(callbackC, {timeout: 2}); // will time out fast
scheduleWork(callbackD); // won't time out

advanceAll(); // runs rAF and postMessage callbacks
advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks

// callbackC should have timed out
// we should have had time to call A also, then we run out of time
expect(callbackLog).toEqual(['C', 'A']);

runRAFCallbacks(); // runs rAF callback
// push time ahead a bit so that we have no idle time
startOfLatestFrame += 16;
drainPostMessageQueue(); // runs postMessage callback, idleTick
advanceOneFrame({timePastFrameDeadline: 16});

// callbackB should have timed out
// but we should not run callbackD because we have no idle time
expect(callbackLog).toEqual(['C', 'A', 'B']);

advanceAll(); // runs rAF and postMessage callbacks
advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks

// we should have run callbackD in the idle time
expect(callbackLog).toEqual(['C', 'A', 'B', 'D']);

advanceAll(); // runs rAF and postMessage callbacks
advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks

// we should not have run anything again, nothing is scheduled
expect(callbackLog).toEqual(['C', 'A', 'B', 'D']);
Expand All @@ -331,7 +335,7 @@ describe('ReactScheduler', () => {
const callbackId = scheduleWork(cb);
expect(cb.mock.calls.length).toBe(0);
cancelScheduledWork(callbackId);
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
expect(cb.mock.calls.length).toBe(0);
});

Expand All @@ -349,7 +353,7 @@ describe('ReactScheduler', () => {
callbackBId = scheduleWork(callbackB);
// Initially doesn't call anything
expect(callbackLog).toEqual([]);
advanceAll();
advanceOneFrame({timeLeftInFrame: 15});
// B should not get called because A cancelled B
expect(callbackLog).toEqual(['A']);
expect(callbackB.mock.calls.length).toBe(0);
Expand Down