Skip to content

Commit

Permalink
[scheduler] 2/n Adding 'schedule' fixture (facebook#12884)
Browse files Browse the repository at this point in the history
* Adding 'schedule' fixture

**what is the change?:**
We need to test the `schedule` module against real live browser APIs. As
a quick solution we're writing a fixture for using in manual testing.
Later we plan on adding automated browser testing, using this or a
similar fixture as the test page.

**why make this change?:**
To further solidify test coverage for `schedule` before making further
improvements/refactors to the module.

**test plan:**
`open fixtures/schedule/index.html` and inspect the results. It should
be clear that things pass.

We also temporarily broke the scheduler and verified that this fixture
demonstrates the problems.

**issue:**
Internal task T29442940

* Made fixture tests display red or green border depending on pass/fail

**what is the change?:**
Added red/green solid/dashed border for test results when using the
schedule fixture.

We also tweaked the timing of the last test because it was on the line
in terms of whether it passed or failed.

**why make this change?:**
To make it faster to use the fixture - it takes more time to read
through the results line by line and check that they match what is
expected.

**test plan:**
Looked at the fixture, and also tried modifying a test to show what it
looks like when something fails.
  • Loading branch information
flarnie authored May 24, 2018
1 parent 345e0a7 commit 76e0707
Show file tree
Hide file tree
Showing 2 changed files with 293 additions and 10 deletions.
293 changes: 293 additions & 0 deletions fixtures/schedule/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
<!DOCTYPE html>
<html style="width: 100%; height: 100%;">
<head>
<meta charset="utf-8">
<title>Schedule Test Page</title>
<style>
.correct {
border: solid green 2px;
}
.incorrect {
border: dashed red 2px;
}
</style>
</head>
<body>
<h1>Schedule Fixture</h1>
<p>
This fixture is for manual testing purposes, and the patterns used in
implementing it should not be used as a model. This is mainly for anyone
working on making changes to the `schedule` module.
</p>
<h2>Tests:</h2>
<ol>
<li>
<button onClick="runTestOne()">Run Test 1</button>
<p>Calls the callback with the frame when not blocked:</p>
<div><b>Expected:</b></div>
<div id="test-1-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-1"></div>
</li>
<li>
<p>Accepts multiple callbacks and calls within frame when not blocked</p>
<button onClick="runTestTwo()">Run Test 2</button>
<div><b>Expected:</b></div>
<div id="test-2-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-2"></div>
</li>
<li>
<p>Schedules callbacks in correct order when they use scheduleWork to schedule themselves</p>
<button onClick="runTestThree()">Run Test 3</button>
<div><b>Expected:</b></div>
<div id="test-3-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-3"></div>
</li>
<li>
<p>Calls timed out callbacks and then any more pending callbacks, defers others if time runs out</p>
<button onClick="runTestFour()">Run Test 4</button>
<div><b>Expected:</b></div>
<div id="test-4-expected">
</div>
<div> -------------------------------------------------</div>
<div> If you see the same above and below it's correct.
<div> -------------------------------------------------</div>
<div><b>Actual:</b></div>
<div id="test-4"></div>
</li>
</ol>
<script src="../../build/dist/react-scheduler.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<script type="text/babel">
const {scheduleWork, cancelWork, now} = ReactScheduler;
function displayTestResult(testNumber) {
const expectationNode = document.getElementById('test-' + testNumber + '-expected');
const resultNode = document.getElementById('test-' + testNumber);
resultNode.innerHTML = latestResults[testNumber - 1].join('<br />');
expectationNode.innerHTML = expectedResults[testNumber - 1].join('<br />');
}
function clearTestResult(testNumber) {
const resultNode = document.getElementById('test-' + testNumber);
resultNode.innerHTML = '';
latestResults[testNumber - 1] = [];
}
function updateTestResult(testNumber, textToAddToResult) {
latestResults[testNumber - 1].push(textToAddToResult);
};
function checkTestResult(testNumber) {

let correct = true;
const expected = expectedResults[testNumber - 1]; // zero indexing
const result = latestResults[testNumber - 1]; // zero indexing
if (expected.length !== result.length) {
correct = false;
} else {
for (let i = 0, len = expected.length; i < len; i++) {
if (expected[i] !== result[i]) {
correct = false;
break;
}
}
}
const currentClass = correct ? 'correct' : 'incorrect';
const previousClass = correct ? 'incorrect' : 'correct';
document.getElementById('test-' + testNumber).classList.remove(previousClass);
document.getElementById('test-' + testNumber).classList.add(currentClass);
}
function logWhenFramesStart(testNumber, cb) {
requestAnimationFrame(() => {
updateTestResult(testNumber, 'frame 1 started');
requestAnimationFrame(() => {
updateTestResult(testNumber, 'frame 2 started');
requestAnimationFrame(() => {
updateTestResult(testNumber, 'frame 3 started... we stop counting now.');
cb();
});
});
});
}
// push in results when we run the test
const latestResults = [
// test 1
[
],
// test 2
[
],
// test 3
[
],
// test 4
[
],
];

const expectedResults = [
// test 1
[
'scheduled Cb1',
'frame 1 started',
'cb1 called with argument of {"didTimeout":false}',
'frame 2 started',
'frame 3 started... we stop counting now.',
],
// test 2
[
'scheduled CbA',
'scheduled CbB',
'frame 1 started',
'cbA called with argument of {"didTimeout":false}',
'cbB called with argument of {"didTimeout":false}',
'frame 2 started',
'frame 3 started... we stop counting now.',
],
// test 3
[
'scheduled CbA',
'scheduled CbB',
'frame 1 started',
'scheduled CbA again',
'cbA0 called with argument of {"didTimeout":false}',
'cbB called with argument of {"didTimeout":false}',
'cbA1 called with argument of {"didTimeout":false}',
'frame 2 started',
'frame 3 started... we stop counting now.',
],
// test 4
[
'scheduled cbA',
'scheduled cbB',
'scheduled cbC',
'scheduled cbD',
'frame 1 started',
'cbC called with argument of {"didTimeout":true}',
'cbA called with argument of {"didTimeout":false}',
'cbA running and taking some time',
'frame 2 started',
'cbB called with argument of {"didTimeout":false}',
'cbD called with argument of {"didTimeout":false}',
'frame 3 started... we stop counting now.',
],
];
function runTestOne() {
// Test 1
// Calls the callback with the frame when not blocked
clearTestResult(1);
const test1Log = [];
const cb1Arguments = [];
const cb1 = (x) => {
updateTestResult(1, 'cb1 called with argument of ' + JSON.stringify(x));
}
scheduleWork(cb1);
updateTestResult(1, 'scheduled Cb1');
logWhenFramesStart(1, () => {
displayTestResult(1);
checkTestResult(1);
});
};

function runTestTwo() {
// Test 2
// accepts multiple callbacks and calls within frame when not blocked
clearTestResult(2);
const cbA = (x) => {
updateTestResult(2, 'cbA called with argument of ' + JSON.stringify(x));
}
const cbB = (x) => {
updateTestResult(2, 'cbB called with argument of ' + JSON.stringify(x));
}
scheduleWork(cbA);
updateTestResult(2, 'scheduled CbA');
scheduleWork(cbB);
updateTestResult(2, 'scheduled CbB');
logWhenFramesStart(2, () => {
displayTestResult(2);
checkTestResult(2);
});
}

function runTestThree() {
// Test 3
// Schedules callbacks in correct order when they use scheduleWork to schedule themselves
clearTestResult(3);
let callbackAIterations = 0;
const cbA = (x) => {
if (callbackAIterations < 1) {
scheduleWork(cbA);
updateTestResult(3, 'scheduled CbA again');
}
updateTestResult(3, 'cbA' + callbackAIterations + ' called with argument of ' + JSON.stringify(x));
callbackAIterations++;
}
const cbB = (x) => {
updateTestResult(3, 'cbB called with argument of ' + JSON.stringify(x));
}
scheduleWork(cbA);
updateTestResult(3, 'scheduled CbA');
scheduleWork(cbB);
updateTestResult(3, 'scheduled CbB');
logWhenFramesStart(3, () => {
displayTestResult(3);
checkTestResult(3);
});
}

function waitForTimeToPass(timeInMs) {
const startTime = Date.now();
const endTime = startTime + timeInMs;
while (Date.now() < endTime) {
// wait...
}
}

function runTestFour() {
// Test 4
// Calls timed out callbacks and then any more pending callbacks, defers others if time runs out
clearTestResult(4);
const cbA = (x) => {
updateTestResult(4, 'cbA called with argument of ' + JSON.stringify(x));
updateTestResult(4, 'cbA running and taking some time');
waitForTimeToPass(35);
}
const cbB = (x) => {
updateTestResult(4, 'cbB called with argument of ' + JSON.stringify(x));
}
const cbC = (x) => {
updateTestResult(4, 'cbC called with argument of ' + JSON.stringify(x));
}
const cbD = (x) => {
updateTestResult(4, 'cbD called with argument of ' + JSON.stringify(x));
}
scheduleWork(cbA); // won't time out
updateTestResult(4, 'scheduled cbA');
scheduleWork(cbB, {timeout: 100}); // times out later
updateTestResult(4, 'scheduled cbB');
scheduleWork(cbC, {timeout: 2}); // will time out fast
updateTestResult(4, 'scheduled cbC');
scheduleWork(cbD); // won't time out
updateTestResult(4, 'scheduled cbD');

// should have run in order of C, A, B, D

logWhenFramesStart(4, () => {
displayTestResult(4);
checkTestResult(4);
});
}
</script type="text/babel">
</body>
</html>
10 changes: 0 additions & 10 deletions packages/react-scheduler/src/__tests__/test_page.html

This file was deleted.

0 comments on commit 76e0707

Please sign in to comment.