<!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>
