Tests: Add IntersectionObserver tests for scroll container clipping

Add tests for the implicit root case where targets are inside scroll
containers with various overflow types:

- overflow:hidden container with target pushed below visible area:
  should NOT be intersecting (currently wrong, shows intersecting).
- overflow:clip container with target pushed below visible area:
  should NOT be intersecting (currently wrong, shows intersecting).
- overflow:hidden container with target at top (visible):
  should be intersecting (correct).

The two failing tests currently reflect wrong behavior because
compute_intersection does not clip against intermediate scroll
containers when walking the containing block chain.
This commit is contained in:
Andreas Kling
2026-03-22 08:42:11 -05:00
committed by Andreas Kling
parent bbadb38881
commit d1b485e6d6
Notes: github-actions[bot] 2026-03-22 19:11:20 +00:00
6 changed files with 131 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<style>
body { margin: 0; }
#clipper {
width: 200px;
height: 200px;
overflow: clip;
}
#spacer {
height: 500px;
}
#target {
width: 50px;
height: 50px;
background: red;
}
</style>
<script src="../include.js"></script>
<div id="clipper">
<div id="spacer"></div>
<div id="target"></div>
</div>
<script>
asyncTest(done => {
// The target is inside an overflow:clip container, pushed below
// the visible area by a spacer. It should NOT be intersecting.
let callbackCount = 0;
let observer = new IntersectionObserver(entries => {
callbackCount++;
entries.forEach(entry => {
println(`callback ${callbackCount}: isIntersecting=${entry.isIntersecting}`);
});
if (callbackCount === 1) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
println(`total callbacks: ${callbackCount}`);
done();
});
});
}
});
observer.observe(document.getElementById("target"));
});
</script>

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<style>
body { margin: 0; }
#scroller {
width: 200px;
height: 200px;
overflow: hidden;
}
#spacer {
height: 500px;
}
#target {
width: 50px;
height: 50px;
background: red;
}
</style>
<script src="../include.js"></script>
<div id="scroller">
<div id="spacer"></div>
<div id="target"></div>
</div>
<script>
asyncTest(done => {
// The target is inside a scroll container with overflow:hidden.
// The spacer pushes the target below the scroll container's visible area.
// With the implicit root (viewport), the target should NOT be intersecting
// because it is clipped by the scroll container.
let callbackCount = 0;
let observer = new IntersectionObserver(entries => {
callbackCount++;
entries.forEach(entry => {
println(`callback ${callbackCount}: isIntersecting=${entry.isIntersecting}`);
});
if (callbackCount === 1) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
println(`total callbacks: ${callbackCount}`);
done();
});
});
}
});
observer.observe(document.getElementById("target"));
});
</script>

View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<style>
body { margin: 0; }
#scroller {
width: 200px;
height: 200px;
overflow: hidden;
}
#target {
width: 50px;
height: 50px;
background: red;
}
</style>
<script src="../include.js"></script>
<div id="scroller">
<div id="target"></div>
</div>
<script>
asyncTest(done => {
// The target is at the top of a scroll container and visible.
// With the implicit root, the target SHOULD be intersecting.
let observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
println(`isIntersecting=${entry.isIntersecting}, ratio=${entry.intersectionRatio}`);
if (entry.isIntersecting) {
done();
}
});
});
observer.observe(document.getElementById("target"));
});
</script>