| <!DOCTYPE html> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src="../resources/intersection-observer-test-utils.js"></script> | |
| <style> | |
| body, html { | |
| margin: 0; | |
| } | |
| pre, #log { | |
| position: absolute; | |
| top: 0; | |
| left: 200px; | |
| } | |
| #target { | |
| width: 100px; | |
| height: 100px; | |
| background-color: green; | |
| } | |
| #occluder { | |
| width: 100px; | |
| height: 100px; | |
| background-color: blue; | |
| } | |
| </style> | |
| <div id="target"></div> | |
| <div id="occluder"></div> | |
| <script> | |
| async_test(t => { | |
| let entries = []; | |
| let delay = 100; | |
| let target = document.getElementById("target"); | |
| let occluder = document.getElementById("occluder"); | |
| assert_true(!!target, "target exists"); | |
| assert_true(!!occluder, "occluder exists"); | |
| let observer = new IntersectionObserver(function(changes) { | |
| entries = entries.concat(changes) | |
| }, {trackVisibility: true, delay: delay}); | |
| observer.observe(target); | |
| entries = entries.concat(observer.takeRecords()); | |
| assert_equals(entries.length, 0, "No initial notifications."); | |
| // The first notification should be sent without delay. | |
| waitForNotification(t, t.step_func(step0)); | |
| function waitForDelay(timerExpiredBeforeLastFrame, nextStep) { | |
| requestAnimationFrame(t.step_func(() => { | |
| if (timerExpiredBeforeLastFrame) { | |
| // New notifications should have been generated during the previous | |
| // frame and delivered by now. | |
| assert_equals(entries.length, 2); | |
| assert_greater_than(entries[1].time - entries[0].time, delay); | |
| assert_false(entries[1].isVisible); | |
| nextStep(); | |
| } else { | |
| // Observer may not have updated yet. Wait for next frame. | |
| let timerExpired = performance.now() - entries[0].time >= delay; | |
| waitForDelay(timerExpired, nextStep); | |
| } | |
| })); | |
| } | |
| function step0() { | |
| assert_equals(entries.length, 1); | |
| assert_true(entries[0].isVisible); | |
| // This should trigger a notification on the next run. | |
| occluder.style.marginTop = "-10px"; | |
| // Enter a rAF loop until the delay timer expires. | |
| waitForDelay(false, step1); | |
| } | |
| function step1() { | |
| occluder.style.marginTop = "10px"; | |
| // This style invalidation should cause a frame to run before the observer | |
| // can generate a notification (due to delay parameter). Make sure the | |
| // notification will still be generated even if we don't force more frames | |
| // with a rAF loop. | |
| t.step_timeout(() => { | |
| assert_equals(entries.length, 3); | |
| assert_true(entries[0].isVisible); | |
| t.done(); | |
| }, 2 * delay); | |
| } | |
| }, "'delay' parameter throttles frequency of notifications."); | |
| </script> |