summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/requestidlecallback
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/requestidlecallback')
-rw-r--r--testing/web-platform/tests/requestidlecallback/META.yml4
-rw-r--r--testing/web-platform/tests/requestidlecallback/basic.html53
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-exception.html22
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-idle-periods.html44
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-iframe.html18
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-invoked.html13
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-multiple-calls.html46
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-removed-frame.html30
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-suspended.html94
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-timeRemaining-cross-realm-method.html25
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-timeout-when-busy.html70
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-timeout.html44
-rw-r--r--testing/web-platform/tests/requestidlecallback/callback-xhr-sync.html17
-rw-r--r--testing/web-platform/tests/requestidlecallback/cancel-invoked.html32
-rw-r--r--testing/web-platform/tests/requestidlecallback/deadline-after-expired-timer.html22
-rw-r--r--testing/web-platform/tests/requestidlecallback/deadline-max-rAF-dynamic.html31
-rw-r--r--testing/web-platform/tests/requestidlecallback/deadline-max-rAF.html21
-rw-r--r--testing/web-platform/tests/requestidlecallback/deadline-max-timeout-dynamic.html31
-rw-r--r--testing/web-platform/tests/requestidlecallback/deadline-max.html20
-rw-r--r--testing/web-platform/tests/requestidlecallback/idlharness.window.js24
-rw-r--r--testing/web-platform/tests/requestidlecallback/resources/post_name_on_load.html7
-rw-r--r--testing/web-platform/tests/requestidlecallback/resources/ric-utils.js14
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