chromium/third_party/blink/web_tests/fast/dom/timer-throttling-hidden-page.html

<html>
<head>
    <script src="../../resources/js-test.js"></script>
    <script src="../../resources/visibility.js"></script>
    <script>
        description('<a href="https://bugs.webkit.org/show_bug.cgi?id=98474">Bug 98474</a>: Throttle DOM timers on hidden pages.');

        jsTestIsAsync = true;
        let testStartTime = 0;
        let timerCount = 0;
        let requestedInterval = 100;
        let timerAlignmentInterval = 1000;

        function testTimer() {
            ++timerCount;
            let promise;

            // Timer 1 runs when the page is visible.
            // Timer 2, 3, 4 run when the page is hidden.
            // Timer 5 runs when the page is visible. It finishes the test.
            if (timerCount == 1) {
                promise = setMainWindowHidden(true);
            } else if (timerCount == 4) {
                promise = setMainWindowHidden(false);
            } else if (timerCount == 5) {
                // Timer 1 and 5 add at least `requestedInterval` of delay.
                //     No throttling, may run as soon as the timeout expires.
                // Timer 2 adds at least `requestedInterval` of delay.
                //     Runs on the first 1-second aligned tick after the
                //     timeout's expiration. Depending on when the timer is
                //     scheduled, this may have no effect.
                // Timer 3 and 4 add at least `timerAlignmentInterval` of delay.
                //     Runs on the first 1-second aligned tick after the
                //     timeout's expiration (which means that it can't be the
                //     same tick as the previous timer invocation).
                //
                // Arbitrary delays introduced by the test environment prevent
                // setting an upper bound on total execution time. Also, since
                // each individual timer could be delayed to run exactly
                // `requestedInterval` before the next 1-second aligned tick,
                // it is not possible to expect that an individual timer runs at
                // least `timerAlignmentInterval` after the previous timer under
                // throttling.
                totalTime = Date.now() - testStartTime;
                shouldBeGreaterThanOrEqual("totalTime", "3 * requestedInterval + 2 * timerAlignmentInterval");
                // The test should run in less than a day. Without this check, the
                // test could pass simply because `testStartTime` was not initialized.
                shouldBeGreaterThanOrEqual("1000 * 60 * 60 * 24", "totalTime");
                finishJSTest();
                return;
            } else {
                promise = Promise.resolve();
            }

            promise.then(() => {
                setTimeout(testTimer, requestedInterval);
            });
        }

        function runTest()
        {
            if (!window.testRunner) {
                debug('This test requires testRunner');
                return;
            }

            var requestedIntervalSpans = document.getElementsByClassName('requestedInterval');
            for (var i = 0; i < requestedIntervalSpans.length; i++)
                requestedIntervalSpans[i].innerText = requestedInterval;

            document.getElementById('alignmentInterval').innerText = timerAlignmentInterval / 1000;

            testRunner.dumpAsText();
            testStartTime = Date.now();
            previousTime = testStartTime;
            setTimeout(testTimer, requestedInterval);
        }
    </script>
</head>
<body onload="runTest()">
    <p>
    This test measures the time taken to fire a <span class="requestedInterval"></span>ms DOM Timer when the page visibility is set to "visible", "hidden", and then back to "visible".  Due to page timer throttling, the timer should fire close to <span id="alignmentInterval"></span>s when page is hidden.  And it should fire close to <span class="requestedInterval"></span>ms, when the page is visible.
    </p>
</body>
</html>