diff options
Diffstat (limited to '')
22 files changed, 682 insertions, 0 deletions
diff --git a/testing/web-platform/tests/requestidlecallback/META.yml b/testing/web-platform/tests/requestidlecallback/META.yml new file mode 100644 index 0000000000..9c829d3c88 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/META.yml @@ -0,0 +1,4 @@ +spec: https://w3c.github.io/requestidlecallback/ +suggested_reviewers: + - farre + - rmcilroy diff --git a/testing/web-platform/tests/requestidlecallback/basic.html b/testing/web-platform/tests/requestidlecallback/basic.html new file mode 100644 index 0000000000..df9c9ef977 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/basic.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback exists</title> +<link rel="author" title="Ross McIlroy" href="mailto:rmcilroy@chromium.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// The window.requestIdleCallback function is used to request callbacks during browser-defined idle time. +test(function() { + assert_equals(typeof window.requestIdleCallback, "function"); +}, "window.requestIdleCallback is defined"); + +// The window.cancelIdleCallback function is used to cancel callbacks scheduled via requestIdleCallback. +test(function() { + assert_equals(typeof window.cancelIdleCallback, "function"); +}, "window.cancelIdleCallback is defined"); + +// The requestIdleCallback method MUST return a long +test(function() { + assert_equals(typeof window.requestIdleCallback(function() {}), "number"); +}, "window.requestIdleCallback() returns a number"); + +// The cancelIdleCallback method MUST return undefined +test(function() { + assert_equals(typeof window.cancelIdleCallback(1), "undefined"); +}, "window.cancelIdleCallback() returns undefined"); + +async_test(function() { + // Check whether requestIdleCallback schedules a callback which gets executed + // and the deadline argument is passed correctly. + requestIdleCallback(this.step_func_done(function(deadline) { + assert_equals(arguments.length, 1, "Only one argument should be passed to callback."); + assert_class_string(deadline, "IdleDeadline"); + assert_equals(typeof deadline.timeRemaining, "function", "IdleDeadline.timeRemaining MUST be a function which returns the time remaining in milliseconds"); + assert_equals(typeof deadline.timeRemaining(), "number", "IdleDeadline.timeRemaining MUST return a double of the time remaining in milliseconds"); + assert_true(deadline.timeRemaining() <= 50, "IdleDeadline.timeRemaining() MUST be less than or equal to 50ms in the future."); + assert_equals(typeof deadline.didTimeout, "boolean", "IdleDeadline.didTimeout MUST be a boolean"); + assert_false(deadline.didTimeout, "IdleDeadline.didTimeout MUST be false if requestIdleCallback wasn't scheduled due to a timeout"); + })); +}, 'requestIdleCallback schedules callbacks'); + +async_test(function() { + // Check whether requestIdleCallback schedules a callback which gets executed + // and the deadline argument is passed correctly. + var handle = requestIdleCallback(this.step_func(function(deadline) { + assert_unreached("callback should not be called if canceled with cancelIdleCallback"); + })); + cancelIdleCallback(handle); + step_timeout(this.step_func_done(), 200); +}, 'cancelIdleCallback cancels callbacks'); + +</script> +<h1>Basic requestIdleCallback Tests</h1> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/callback-exception.html b/testing/web-platform/tests/requestidlecallback/callback-exception.html new file mode 100644 index 0000000000..fecda221de --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-exception.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset=utf-8> +<title>requestIdleCallback callback exception reported to error handler</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + var custom_exception = 'requestIdleCallbackException'; + setup({allow_uncaught_exception : true}); + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + addEventListener("error",function(e) { + t.step(function() { + assert_equals(e.error.message, custom_exception); + t.done(); + }) + }); + window.requestIdleCallback(function () { + throw new Error(custom_exception); + }); + }, "requestIdleCallback callback exceptions are reported to error handler"); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-idle-periods.html b/testing/web-platform/tests/requestidlecallback/callback-idle-periods.html new file mode 100644 index 0000000000..3c2de61bfe --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-idle-periods.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback callback behavior during idle periods.</title> +<meta name="timeout" content="long"> +<link rel="author" title="Ross McIlroy" href="mailto:rmcilroy@chromium.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +async_test(function() { + // Check that if an idle callback calls requestIdleCallback, the new callback + // doesn't get the same deadline (i.e., runs in a new idle period). + var previous_deadline = undefined; + var idle_callbacks_remaining = 10; + var rIC = this.step_func(function(deadline) { + var now = performance.now(); + var remaining = deadline.timeRemaining(); + var new_deadline = now + remaining; + if (previous_deadline != undefined) { + assert_true(new_deadline > previous_deadline, "A requestIdleCallback scheduled during an idle period should be called back with a deadline greater than that in the current idle period."); + } + + // Schedule a new requestIdleCallback. + if (--idle_callbacks_remaining > 0) { + previous_deadline = new_deadline; + requestIdleCallback(rIC); + } else { + this.done(); + } + }); + + // Spin an empty rAF loop to cause an idle period each frame. + var idle_task_posted = false; + requestAnimationFrame(function rAFLoop() { + if (!idle_task_posted) { + requestIdleCallback(rIC); + idle_task_posted = true; + } + requestAnimationFrame(rAFLoop); + }); +}, 'Check that if an idle callback calls requestIdleCallback the new callback doesn\'t run in the current idle period.'); +</script> +<h1>Test of requestIdleCallback idle period behavior</h1> +<p>This test validates that window.requestIdleCallback deals with callbacks during idle periods correctly.</p> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/callback-iframe.html b/testing/web-platform/tests/requestidlecallback/callback-iframe.html new file mode 100644 index 0000000000..8ec08a804a --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-iframe.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<iframe style="display:none" id="frame"></iframe> +<script> + async_test(function (t) { + let frame = document.getElementById("frame"); + frame.contentWindow.test = function() { + frame.contentWindow.requestIdleCallback(t.step_func_done()); + } + + frame.contentWindow.test(); + }); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-invoked.html b/testing/web-platform/tests/requestidlecallback/callback-invoked.html new file mode 100644 index 0000000000..dc52f1422b --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-invoked.html @@ -0,0 +1,13 @@ +<!doctype html> +<meta charset=utf-8> +<meta name="timeout" content="long"> +<title>requestIdleCallback callback must be called eventually</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + window.requestIdleCallback(t.step_func_done()); + }, "requestIdleCallback callback is invoked at least once before the timeout"); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-multiple-calls.html b/testing/web-platform/tests/requestidlecallback/callback-multiple-calls.html new file mode 100644 index 0000000000..7bb524beb4 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-multiple-calls.html @@ -0,0 +1,46 @@ +<!doctype html> +<meta charset=utf-8> +<title>multiple calls to requestIdleCallback</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + let option = {timeout: 50}; + + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + var counter = 0; + function f(c) { + assert_equals(counter, c); + if (counter === 49) { + t.done(); + } + + ++counter; + } + for (var i = 0; i < 100; ++i) { + let j = i; + window.requestIdleCallback(t.step_func(function () { f(j) }), option); + } + }, "requestIdleCallback callbacks should be invoked in order (called iteratively)"); + + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + var counter = 0; + + function f(c) { + assert_equals(counter, c); + if (counter === 49) { + t.done(); + } + + ++counter; + window.requestIdleCallback(t.step_func(function () { f(c + 1) }), option); + } + + window.requestIdleCallback(t.step_func(function () { f(0) }), option); + }, "requestIdleCallback callbacks should be invoked in order (called recursively)"); + + let generateIdlePeriods = _ => requestAnimationFrame(generateIdlePeriods); + generateIdlePeriods(); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-removed-frame.html b/testing/web-platform/tests/requestidlecallback/callback-removed-frame.html new file mode 100644 index 0000000000..ca63f68f8a --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-removed-frame.html @@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<title>requestIdleCallback on removed frame shouldn't call back</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + + function start() { + var frame = document.createElement('iframe'); + frame.addEventListener('load', _ => connect(frame), {once:true}); + frame.src = "about:blank"; + document.body.appendChild(frame); + } + + function connect(frame) { + var contentWindow = frame.contentWindow; + contentWindow.requestIdleCallback(_ => callback0(frame, contentWindow)); + t.step_timeout(function() { t.done(); }, 1000); + } + + function callback0(f, w) { + document.body.removeChild(f); + w.requestIdleCallback(t.unreached_func("requestIdleCallback callback should not trigger the callback")); + } + + addEventListener('load', start, {once:true}); + }, "calling requestIdleCallback on a contentWindow from a removed iframe should not trigger the callback"); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-suspended.html b/testing/web-platform/tests/requestidlecallback/callback-suspended.html new file mode 100644 index 0000000000..511ec128d6 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-suspended.html @@ -0,0 +1,94 @@ +<!doctype html> +<meta charset=utf-8> +<title>Dispatching idle callbacks should be able to be suspended and then resumed</title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + function withEventListener(target, event, handler) { + handler = handler || (e => e); + return new Promise(resolve => { + let wrapper = function(e) { + let result = handler(e); + if (!result) { + return; + } + + resolve(result); + } + target.addEventListener(event, wrapper, { once: true }); + }); + } + + function makePostBackUrl(name) { + return new URL('resources/post_name_on_load.html?name=' + name, + window.location).href; + } + + function waitForMessage(message, handler) { + return withEventListener(window, 'message', e => (e.data === message) && handler(e));; + } + + function withWindow(name) { + let win = window.open(makePostBackUrl(name)) + return waitForMessage(name, _ => win); + } + + function navigateWindow(win, name) { + win.location = makePostBackUrl(name); + return waitForMessage(name, _ => win); + } + + function waitDuration(delay) { + return new Promise(resolve => { + step_timeout(resolve, delay); + }) + } + + function goBack(win) { + var p = withEventListener(win, 'pagehide'); + win.history.back(); + return p; + } + + promise_test(t => { + let idleCalled = false; + let running = true; + return withWindow('foo') + .then(win => { + let callback = function(d) { + idleCalled = true; + if (running) { + win.requestIdleCallback(callback); + } + }; + + win.requestIdleCallback(callback); + + return navigateWindow(win, 'bar') + .then(_ => idleCalled = false) + .then(_ => waitDuration(2000)) + .then(_ => { + assert_false(idleCalled, "idle callback shouldn't have been called yet"); + return goBack(win); + }) + .then(_ => Promise.race([ + // At this point it's a matter of having bfcache ... + waitDuration(2000) + .then(_ => { + assert_true(idleCalled, "idle callback should've been called by now"); + running = false; + }), + // ... or not. If not, we expect a load event. + waitForMessage("foo", _ => win) + ])) + .then(_ => win.close()) + .catch(e => { + win.close(); + throw e; + }) + }); + }); + +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-timeRemaining-cross-realm-method.html b/testing/web-platform/tests/requestidlecallback/callback-timeRemaining-cross-realm-method.html new file mode 100644 index 0000000000..383479d64a --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-timeRemaining-cross-realm-method.html @@ -0,0 +1,25 @@ +<!doctype html><!-- webkit-test-runner [ RequestIdleCallbackEnabled=true ] --> +<meta charset="utf-8"> +<meta name="timeout" content="long"> +<title>IdleDeadline::timeRemaining() uses relevant global object as a high-res timestamp origin</title> +<link rel="help" href="https://w3c.github.io/requestidlecallback/#dom-idledeadline-timeremaining"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +const t = async_test(); +t.step_timeout(() => { + const iframeDelayed = document.createElement("iframe"); + iframeDelayed.onload = t.step_func(() => { + requestIdleCallback(t.step_func_done(deadline => { + assert_approx_equals( + iframeDelayed.contentWindow.IdleDeadline.prototype.timeRemaining.call(deadline), + deadline.timeRemaining(), + 5, + ); + })); + }); + document.body.append(iframeDelayed); +}, 1000); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-timeout-when-busy.html b/testing/web-platform/tests/requestidlecallback/callback-timeout-when-busy.html new file mode 100644 index 0000000000..39e17f7b73 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-timeout-when-busy.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback deals with timeouts correctly</title> +<meta name="timeout" content="long"> +<link rel="author" title="Ross McIlroy" href="mailto:rmcilroy@chromium.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +async_test(function() { + // Check whether requestIdleCallback with a timeout works when the event loop + // is busy. + var busy_loop_iterations_remaining = 10; // Should take 20 * 40 = 400ms + var idle_callback_scheduled; + var idle_callback = this.step_func_done(function(deadline) { + assert_false(deadline.didTimeout, "IdleDeadline.didTimeout MUST be false if requestIdleCallback wasn't scheduled due to a timeout"); + assert_equals(busy_loop_iterations_remaining, 0, "Busy event loop should be finished by the time we get scheduled"); + }); + + var busy_loop_iterations_remaining = 10; // Should take 20 * 40 = 400ms + step_timeout(this.step_func(function busyLoop() { + var start_time = performance.now(); + if (!idle_callback_scheduled) { + idle_callback_scheduled = start_time; + requestIdleCallback(idle_callback); + } + + // Use up more than a frames worth of budget. + while (performance.now() - start_time < 40) { + } + if (busy_loop_iterations_remaining > 0) { + busy_loop_iterations_remaining--; + step_timeout(busyLoop); + } + })); +}, 'requestIdleCallback not scheduled when event loop is busy.'); + +async_test(function() { + // Check whether requestIdleCallback with a timeout works when the event loop + // is busy. + var busy_loop_iterations_remaining = 10; // Should take 20 * 40 = 400ms + var timeout = 200; + var idle_callback_scheduled; + var idle_callback = this.step_func_done(function(deadline) { + var time_delta = performance.now() - idle_callback_scheduled; + assert_true(time_delta >= timeout, "Should only have been run after timeout"); + assert_true(deadline.timeRemaining() == 0, "IdleDeadline.timeRemaining MUST be equal to zero if requestIdleCallback was scheduled due to a timeout"); + assert_true(deadline.didTimeout, "IdleDeadline.didTimeout MUST be true if requestIdleCallback was scheduled due to a timeout"); + assert_true(busy_loop_iterations_remaining > 0, "Busy event loop should still be going"); + }); + + step_timeout(this.step_func(function busyLoop() { + var start_time = performance.now(); + if (!idle_callback_scheduled) { + idle_callback_scheduled = start_time; + requestIdleCallback(idle_callback, { timeout: timeout }); + } + + // Use up more than a frames worth of budget. + while (performance.now() - start_time < 40) { + } + if (busy_loop_iterations_remaining > 0) { + busy_loop_iterations_remaining--; + step_timeout(busyLoop); + } + })); +}, 'requestIdleCallback scheduled with timeout when event loop is busy.'); + +</script> +<h1>Test of requestIdleCallback timeout behavior</h1> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/callback-timeout.html b/testing/web-platform/tests/requestidlecallback/callback-timeout.html new file mode 100644 index 0000000000..248864f3a1 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-timeout.html @@ -0,0 +1,44 @@ +<!doctype html> +<meta charset=utf-8> +<title>requestIdleCallback timeout callback must be called with didTimeout equal to true</title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + var counter = 0; + + function g(deadline) { + assert_true(deadline.didTimeout) + t.done(); + } + + function f(deadline) { + assert_false(deadline.didTimeout); + window.requestIdleCallback(t.step_func(g), {timeout:300}); + + var d = Date.now() + 500; + while (Date.now() < d) { + + } + } + window.requestIdleCallback(t.step_func(f)); + }, "requestIdleCallback callback should time out"); + + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + function g(deadline) { + assert_false(deadline.didTimeout) + t.done(); + } + + function f(deadline) { + assert_false(deadline.didTimeout); + window.requestIdleCallback(t.step_func(g), {timeout:100000}); + } + window.requestIdleCallback(t.step_func(f)); + }, "requestIdleCallback callback should not time out"); + +</script> diff --git a/testing/web-platform/tests/requestidlecallback/callback-xhr-sync.html b/testing/web-platform/tests/requestidlecallback/callback-xhr-sync.html new file mode 100644 index 0000000000..d0aa5d28d6 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/callback-xhr-sync.html @@ -0,0 +1,17 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + async_test(function (t) { + requestIdleCallback(function() { + requestIdleCallback(t.step_func_done(function () {})) + var xhr = new XMLHttpRequest(); + xhr.open("GET", "www.emample.com", false); + xhr.onload = t.step_func(function () {}); + xhr.send(null); + }); + }, "re-schedule idle callbacks after sync xhr"); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/cancel-invoked.html b/testing/web-platform/tests/requestidlecallback/cancel-invoked.html new file mode 100644 index 0000000000..9fb77d65dc --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/cancel-invoked.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>cancelling idle requests</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + test(function (t) { + window.cancelIdleCallback(42); + assert_true(true); + }, "cancelIdleCallback does nothing if there is no callback with the given handle"); + + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + var neverCalled = true; + var handle = window.requestIdleCallback(function () { + neverCalled = false; + }); + window.cancelIdleCallback(handle); + + t.step_timeout(function() { + assert_true(neverCalled); + t.done(); + }, 2000); + }, "A cancelled callback is never invoked"); + + async_test(function (t) { + var handle = requestIdleCallback(t.step_func_done(function () { + cancelIdleCallback(handle); + })); + }, "Cancelling the currently executing idle callback should be allowed"); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/deadline-after-expired-timer.html b/testing/web-platform/tests/requestidlecallback/deadline-after-expired-timer.html new file mode 100644 index 0000000000..47396ea5ed --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/deadline-after-expired-timer.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset=utf-8> +<title>The deadline after an expired timer must not be negative</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + async_test(function(t) { + setTimeout(() => { + + requestIdleCallback( + t.step_func((deadline) => { + assert_false(deadline.didTimeout); + assert_greater_than(deadline.timeRemaining(), 0); + t.done(); + }), + { timeout: 1000 } + ); + + }, 0); + }); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/deadline-max-rAF-dynamic.html b/testing/web-platform/tests/requestidlecallback/deadline-max-rAF-dynamic.html new file mode 100644 index 0000000000..43eebd7641 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/deadline-max-rAF-dynamic.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback max idle period deadline (requestAnimationFrame).</title> +<meta name="timeout" content="long"> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/ric-utils.js"></script> +<script> + +promise_test(async () => { + for (let i = 0; i < getRICRetryCount(); ++i) { + const {before, after} = await new Promise(resolve => requestIdleCallback(async deadline => { + const before = deadline.timeRemaining(); + const animationFramePromise = new Promise(requestAnimationFrame); + const after = deadline.timeRemaining(); + + // Waiting till rAF is handled before the next iteration, to avoid residual callacks between iterations. + await animationFramePromise; + resolve({before, after}) + })) + + assert_less_than_equal(after, before) + assert_less_than_equal(after, getPendingRenderDeadlineCap()) + } + +}, 'Check that the deadline is changed if there is a new requestAnimationFrame from within requestIdleCallback.'); +</script> +<h1>Test of requestIdleCallback deadline behavior</h1> +<p>The test can pass accidentally as idle deadlines have a maximum but they can always be shorter. +It runs multiple times to expose potential failures.</p> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/deadline-max-rAF.html b/testing/web-platform/tests/requestidlecallback/deadline-max-rAF.html new file mode 100644 index 0000000000..314f250254 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/deadline-max-rAF.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback max idle period deadline (requestAnimationFrame).</title> +<meta name="timeout" content="long"> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/ric-utils.js"></script> +<script> + +promise_test(async done => { + for (let i = 0; i < getRICRetryCount(); ++i) { + requestAnimationFrame(() => {}) + assert_less_than_equal(await getDeadlineForNextIdleCallback(), getPendingRenderDeadlineCap()) + } + +}, 'Check that the deadline is less than 16ms when there is a pending animation frame.'); +</script> +<h1>Test of requestIdleCallback deadline behavior</h1> +<p>The test can pass accidentally as idle deadlines have a maximum but they can always be shorter. +It runs multiple times to expose potential failures.</p> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/deadline-max-timeout-dynamic.html b/testing/web-platform/tests/requestidlecallback/deadline-max-timeout-dynamic.html new file mode 100644 index 0000000000..169e6db548 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/deadline-max-timeout-dynamic.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback max idle period deadline (dynamic timoeout).</title> +<meta name="timeout" content="long"> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/ric-utils.js"></script> +<script> + +promise_test(async () => { + for (let i = 0; i < getRICRetryCount(); ++i) { + for (const timeout of [10, 20, 30]) { + const {before, after} = await new Promise(resolve => requestIdleCallback(async deadline => { + const before = deadline.timeRemaining(); + const timerPromise = new Promise(resolve => step_timeout(resolve, timeout)); + const after = deadline.timeRemaining(); + await timerPromise; + resolve({before, after}) + })) + + assert_less_than_equal(after, before) + assert_less_than_equal(after, timeout) + } + } + +}, 'Check that the deadline is changed if there is a new timeout from within requestIdleCallback.'); +</script> +<h1>Test of requestIdleCallback deadline behavior</h1> +<p>The test can pass accidentally as idle deadlines have a maximum but they can always be shorter. +It runs multiple times to expose potential failures.</p> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/deadline-max.html b/testing/web-platform/tests/requestidlecallback/deadline-max.html new file mode 100644 index 0000000000..e33341ac9d --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/deadline-max.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>window.requestIdleCallback max idle period deadline.</title> +<meta name="timeout" content="long"> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/ric-utils.js"></script> +<script> + +promise_test(async done => { + for (let i = 0; i < getRICRetryCount(); ++i) + assert_less_than_equal(await getDeadlineForNextIdleCallback(), 50) + +}, 'Check that the deadline is less than 50ms.'); +</script> +<h1>Test of requestIdleCallback deadline behavior</h1> +<p>This test validates that deadlines returned for requestIdleCallback are less than 50ms.</p> +<p>The test can pass accidentally as idle deadlines have a maximum but they can always be shorter. +It runs multiple times to expose potential failures.</p> +<div id="log"></div> diff --git a/testing/web-platform/tests/requestidlecallback/idlharness.window.js b/testing/web-platform/tests/requestidlecallback/idlharness.window.js new file mode 100644 index 0000000000..69cd5a49b0 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/idlharness.window.js @@ -0,0 +1,24 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://w3c.github.io/requestidlecallback/ + +'use strict'; + +idl_test( + ['requestidlecallback'], + ['html', 'dom'], + async idl_array => { + idl_array.add_objects({ + IdleDeadline: ['deadline'], + Window: ['window'], + }); + + await new Promise(resolve => { + requestIdleCallback(d => { + self.deadline = d; + resolve(); + }, { timeout: 100 }); + }); + } +); diff --git a/testing/web-platform/tests/requestidlecallback/resources/post_name_on_load.html b/testing/web-platform/tests/requestidlecallback/resources/post_name_on_load.html new file mode 100644 index 0000000000..4679a6e6ec --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/resources/post_name_on_load.html @@ -0,0 +1,7 @@ +<!doctype html> +<script> + addEventListener('load', _ => { + let params = new URLSearchParams(window.location.search); + window.opener.postMessage(params.get('name'), '*'); + }); +</script> diff --git a/testing/web-platform/tests/requestidlecallback/resources/ric-utils.js b/testing/web-platform/tests/requestidlecallback/resources/ric-utils.js new file mode 100644 index 0000000000..d6d22767a9 --- /dev/null +++ b/testing/web-platform/tests/requestidlecallback/resources/ric-utils.js @@ -0,0 +1,14 @@ +function getDeadlineForNextIdleCallback() { + return new Promise( + resolve => + requestIdleCallback(deadline => resolve(deadline.timeRemaining())) + ); +} + +function getPendingRenderDeadlineCap() { + return 1000 / 60; +} + +function getRICRetryCount() { + return 10; +}
\ No newline at end of file |