Base: Replace setInterval test page with a more thorough timer test page

Ensure we test both setTimeout and setInterval (and their cancellation
methods), and test scenarios such as raising exceptions in the callback,
passing extra arguments, etc.
This commit is contained in:
Timothy Flynn 2022-03-04 10:36:21 -05:00 committed by Andreas Kling
parent 7b54845c8e
commit 8156ec5da8
3 changed files with 195 additions and 24 deletions

View file

@ -1,23 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>setInterval() test</title>
<script>
document.addEventListener("DOMContentLoaded", function () {
var output = document.getElementById("output");
var counter = 0;
function updateOutput () {
output.innerHTML = `setInterval() was called ${counter} times!`;
}
updateOutput();
setInterval(function () {
counter++;
updateOutput();
}, 1000);
});
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>

View file

@ -0,0 +1,194 @@
<!DOCTYPE html>
<html>
<head>
<style>
.pass, .fail, .running {
height: 30px;
line-height: 30px;
color: white;
display: block;
border: 1px solid black;
margin: 3px;
padding: 3px;
}
.pass { background-color: green; }
.fail { background-color: red; }
.running { background-color: blue; }
</style>
</head>
<body>
<script>
const bindMethodsForTest = (method, maxInvocations) => {
let failures = 0;
const span = document.createElement("span");
span.innerHTML = `Running: ${method}`;
span.setAttribute("class", "running");
span.id = method;
const pass = () => {
if (failures > 0) {
return;
}
++pass.invocationCount;
if (pass.invocationCount > maxInvocations) {
fail(`setTimeout callback triggered more than ${maxInvocations} time(s)`);
} else if (pass.invocationCount === maxInvocations) {
const span = document.getElementById(method);
span.innerHTML = `Pass! ${method}`;
span.setAttribute("class", "pass");
}
};
const fail = message => {
const span = document.getElementById(method);
span.innerHTML = `Fail! ${method}: ${message}`;
span.setAttribute("class", "fail");
++failures;
};
document.body.appendChild(span);
pass.invocationCount = 0;
return [pass, fail];
};
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout triggered immediately", 1);
setTimeout(pass, 0);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout triggered after 1 second", 1);
setTimeout(pass, 1000);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout triggered with string callback", 1);
window.setTimeoutStringCallback = pass;
setTimeout("setTimeoutStringCallback();", 500);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout cancelled before execution", 1);
pass();
const id = setTimeout(pass, 1000);
clearTimeout(id);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout triggered with callback that throws", 1);
// The error should be reported, but should not halt execution of other JavaScript.
setTimeout(() => {
setTimeout(pass, 500);
throw new Error();
}, 500);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout callback unaffected by cancelling another timer", 1);
const id = setTimeout(pass, 1000);
clearTimeout(id + 1);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setTimeout callback triggered with extra arguments", 1);
setTimeout((integer, string, date) => {
if (integer !== 12389) {
fail(`Expected first argument to be the integer 12389, got ${integer}`);
} else if (string !== "foo") {
fail(`Expected second argument to be the string foo, got ${string}`);
} else if (!(date instanceof Date)) {
fail(`Expected third argument to be a date, got ${date}`);
}
pass();
}, 600, 12389, "foo", new Date());
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval repeats callback until cancelled", 5);
const id = setInterval(pass, 500);
setTimeout(() => clearInterval(id), 2600);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval cancelled before execution", 1);
pass();
const id = setInterval(pass, 1000);
clearInterval(id);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval cancelled during execution", 1);
const id = setInterval(() => {
pass();
clearInterval(id);
}, 500);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval triggered with string callback", 6);
window.setIntervalStringCallback = pass;
const id = setInterval("setIntervalStringCallback();", 300);
setTimeout(() => clearInterval(id), 1900);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval triggered with callback that throws", 3);
let callCount = 0;
const id = setInterval(() => {
++callCount;
pass();
if (callCount === 2) {
throw new Error();
} else if (callCount === 3) {
clearInterval(id);
}
}, 500);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval callback unaffected by cancelling another timer", 1);
const id = setInterval(() => {
pass();
clearInterval(id);
}, 1000);
clearInterval(id + 1);
})();
(() => {
const [pass, fail] = bindMethodsForTest("setInterval callback triggered with extra arguments", 1);
const id = setInterval((integer, string, date) => {
if (integer !== 12389) {
fail(`Expected first argument to be the integer 12389, got ${integer}`);
} else if (string !== "foo") {
fail(`Expected second argument to be the string foo, got ${string}`);
} else if (!(date instanceof Date)) {
fail(`Expected third argument to be a date, got ${date}`);
}
pass();
clearInterval(id);
}, 600, 12389, "foo", new Date());
})();
</script>
</body>
</html>

View file

@ -152,7 +152,7 @@
<li><a href="qsa.html">querySelectorAll()</a></li>
<li><a href="innerHTML.html">innerHTML()</a></li>
<li><a href="demo.html">fun demo</a></li>
<li><a href="set-interval.html">setInterval()</a></li>
<li><a href="set-timeout-and-interval.html">setTimeout() and setInterval()</a></li>
<li><a href="location.html">window.location property</a></li>
<li><a href="script-preparation-test.html">Test for the early return steps 6-8 of the "prepare a script" algorithm</a></li>
<li><a href="async-js.html">Basic test for async functions and their integration with the LibWeb event loop</a></li>