summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/intersection-observer/v2
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/intersection-observer/v2
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/intersection-observer/v2')
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/animated-occlusion.html73
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/blur-filter.html65
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/box-shadow.html67
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/cross-origin-effects.sub.html65
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/cross-origin-occlusion.sub.html69
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/delay-test.html89
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/drop-shadow-filter-vertical-rl.html66
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/iframe-target.html45
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/inline-occlusion.html62
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/position-absolute-overflow-visible-and-not-visible.html51
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/position-relative.html49
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/scaled-target.html62
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/simple-effects.html72
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html71
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/simple-occlusion.html67
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/text-editor-occlusion.html62
-rw-r--r--testing/web-platform/tests/intersection-observer/v2/text-shadow.html70
17 files changed, 1105 insertions, 0 deletions
diff --git a/testing/web-platform/tests/intersection-observer/v2/animated-occlusion.html b/testing/web-platform/tests/intersection-observer/v2/animated-occlusion.html
new file mode 100644
index 0000000000..fa69733b9f
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/animated-occlusion.html
@@ -0,0 +1,73 @@
+<!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;
+}
+@keyframes rotate {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(45deg);
+ }
+}
+#occluder {
+ will-change: transform;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+</style>
+
+<div id="target"></div>
+<div id="occluder"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an animated occluding element.", delay);
+
+function step0() {
+ occluder.style.animation = "rotate .1s linear";
+ step_timeout(() => {
+ runTestCycle(step1, "occluder.style.animation = 'rotate .1s linear'", delay);
+ }, 50);
+ checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, vw, 0, vh, true, true]);
+}
+
+function step1() {
+ checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, vw, 0, vh, true, false]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/blur-filter.html b/testing/web-platform/tests/intersection-observer/v2/blur-filter.html
new file mode 100644
index 0000000000..8cf63066e1
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/blur-filter.html
@@ -0,0 +1,65 @@
+<!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 {
+ margin-top: 10px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ filter: blur(50px);
+}
+</style>
+
+<div id="target"></div>
+<div id="occluder"></div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
+
+function step0() {
+ // Occluding elements with opacity=0 should not affect target visibility.
+ occluder.style.opacity = "0";
+ runTestCycle(step2, "occluder.style.opacity = 0", delay);
+
+ // First notification should report occlusion due to blur filter.
+ checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+}
+
+function step2() {
+ checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/box-shadow.html b/testing/web-platform/tests/intersection-observer/v2/box-shadow.html
new file mode 100644
index 0000000000..765fa8b2d5
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/box-shadow.html
@@ -0,0 +1,67 @@
+<!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;
+}
+iframe {
+ width: 100px;
+ height: 100px;
+ border: 0;
+}
+#box-shadow {
+ display: inline-block;
+ box-shadow: -50px -50px 0 50px rgba(255, 0, 0, 0.7);
+}
+</style>
+
+<iframe id=target srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe><div id=box-shadow></div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("box-shadow");
+ 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing an iframe element.", delay);
+
+function step0() {
+ occluder.style.boxShadow = "none";
+ runTestCycle(step1, 'occluder.style.boxShadow = "none"', delay);
+ assert_equals(entries.length, 1, "Initial notification.");
+ assert_equals(entries[0].isVisible, false, "Initially occluded.");
+}
+
+function step1() {
+ occluder.style.boxShadow = "";
+ runTestCycle(step2, 'occluder.style.boxShadow = ""', delay);
+ assert_equals(entries.length, 2, "Notification after removing box shadow.");
+ assert_equals(entries[1].isVisible, true, "Visible when box shadow removed.");
+}
+
+function step2() {
+ assert_equals(entries.length, 3, "Notification after re-adding box shadow.");
+ assert_equals(entries[2].isVisible, false, "Occluded when box shadow re-added.");
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/cross-origin-effects.sub.html b/testing/web-platform/tests/intersection-observer/v2/cross-origin-effects.sub.html
new file mode 100644
index 0000000000..5f328bec99
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/cross-origin-effects.sub.html
@@ -0,0 +1,65 @@
+<!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>
+pre, #log {
+ position: absolute;
+ top: 0;
+ left: 200px;
+}
+</style>
+
+<div id="container">
+ <iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/intersection-observer/resources/v2-subframe.html"></iframe>
+</div>
+
+<script>
+async_test(function(t) {
+ let container = document.getElementById("container");
+ let iframe = document.querySelector("iframe");
+
+ function step0(event) {
+ assert_equals(event.data,"");
+ }
+
+ function step1(event) {
+ container.style.opacity = "0.99";
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([true]));
+ }
+
+ function step2(event) {
+ container.style.opacity = "";
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([false]));
+ }
+
+ function step3(event) {
+ container.style.transform = "skew(30deg)";
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([true]));
+ }
+
+ function step4(event) {
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([false]));
+ }
+
+ let steps = [step0, step1, step2, step3, step4];
+
+ window.addEventListener("message", event => {
+ if (steps.length) {
+ t.step(steps.shift(), t, event);
+ waitForFrame(t, () => {
+ iframe.contentWindow.postMessage("", "*")
+ });
+ } else {
+ t.done();
+ }
+ });
+
+}, "Intersection observer V2 test with visual effects on iframe.");
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/cross-origin-occlusion.sub.html b/testing/web-platform/tests/intersection-observer/v2/cross-origin-occlusion.sub.html
new file mode 100644
index 0000000000..4c2f286afb
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/cross-origin-occlusion.sub.html
@@ -0,0 +1,69 @@
+<!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>
+pre, #log {
+ position: absolute;
+ top: 0;
+ left: 200px;
+}
+iframe {
+ width: 300px;
+ height: 150px;
+ border: none;
+}
+#occluder {
+ will-change: transform;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+
+<iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/intersection-observer/resources/v2-subframe.html"></iframe>
+<div id="occluder"></div>
+
+<script>
+async_test(function(t) {
+ let iframe = document.querySelector("iframe");
+ let occluder = document.getElementById("occluder");
+
+ function step0(event) {
+ assert_equals(event.data,"");
+ }
+
+ function step1(event) {
+ occluder.style.marginTop = "-150px";
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([true]));
+ }
+
+ function step2(event) {
+ occluder.style.marginTop = "";
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([false]));
+ }
+
+ function step3(event) {
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([true]));
+ }
+
+ let steps = [step0, step1, step2, step3];
+
+ window.addEventListener("message", event => {
+ if (steps.length) {
+ t.step(steps.shift(), t, event);
+ waitForFrame(t, () => {
+ iframe.contentWindow.postMessage("", "*");
+ });
+ } else {
+ t.done();
+ }
+ });
+
+}, "Intersection observer V2 test with occlusion of target in iframe.");
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/delay-test.html b/testing/web-platform/tests/intersection-observer/v2/delay-test.html
new file mode 100644
index 0000000000..e3906ea2c2
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/delay-test.html
@@ -0,0 +1,89 @@
+<!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>
diff --git a/testing/web-platform/tests/intersection-observer/v2/drop-shadow-filter-vertical-rl.html b/testing/web-platform/tests/intersection-observer/v2/drop-shadow-filter-vertical-rl.html
new file mode 100644
index 0000000000..fc5b145e1f
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/drop-shadow-filter-vertical-rl.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<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: 150px;
+}
+#target {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ float: left;
+}
+#occluder {
+ float: left;
+ margin-left: 10px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ filter: drop-shadow(-50px 0);
+ writing-mode: vertical-rl;
+}
+</style>
+
+<div id="target"></div>
+<div id="occluder"></div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
+
+function step0() {
+ // Occluding elements with opacity=0 should not affect target visibility.
+ occluder.style.opacity = "0";
+ runTestCycle(step2, "occluder.style.opacity = 0", delay);
+
+ // First notification should report occlusion due to drop shadow filter.
+ checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+}
+
+function step2() {
+ checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/iframe-target.html b/testing/web-platform/tests/intersection-observer/v2/iframe-target.html
new file mode 100644
index 0000000000..53fbff86b7
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/iframe-target.html
@@ -0,0 +1,45 @@
+<!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;
+}
+iframe {
+ width: 150px;
+ height: 100px;
+ border: 0;
+}
+</style>
+
+<iframe srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+
+runTestCycle(function() {
+ target = document.querySelector("iframe");
+ assert_true(!!target, "target exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing an iframe element.", delay);
+
+function step0() {
+ checkLastEntry(entries, 0, [0, 150, 0, 100, 0, 150, 0, 100, 0, 800, 0, 600, true, true]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/inline-occlusion.html b/testing/web-platform/tests/intersection-observer/v2/inline-occlusion.html
new file mode 100644
index 0000000000..e4b097e62a
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/inline-occlusion.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<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;
+}
+.testdiv {
+ font-size: 24px;
+}
+</style>
+
+<div class="testdiv">This is the <span id="target">target</span>.</div>
+<div class="testdiv" id="occluder">This is the occluder.</div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
+
+function step0() {
+ occluder.style.marginTop = "-10px";
+ runTestCycle(step1, "occluder.style.marginTop = '-10px'", delay);
+ assert_equals(entries.length, 1);
+ assert_true(entries[0].isVisible);
+}
+
+function step1() {
+ // Occluding elements with opacity=0 should not affect target visibility.
+ occluder.style.opacity = "0";
+ runTestCycle(step2, "occluder.style.opacity = 0", delay);
+ assert_equals(entries.length, 2);
+ assert_false(entries[1].isVisible);
+}
+
+function step2() {
+ assert_equals(entries.length, 3);
+ assert_true(entries[2].isVisible);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/position-absolute-overflow-visible-and-not-visible.html b/testing/web-platform/tests/intersection-observer/v2/position-absolute-overflow-visible-and-not-visible.html
new file mode 100644
index 0000000000..c74d4c2021
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/position-absolute-overflow-visible-and-not-visible.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<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>
+ html, body {
+ margin: 0;
+ padding: 0;
+ height: 200px;
+ width: 100%;
+ }
+ #parent {
+ position: relative;
+ height: 200px;
+ width: 200px;
+ background-color: rgb(250, 221, 221);
+ overflow-y: clip;
+ overflow-x: visible;
+ }
+ #child {
+ background-color: rgb(208, 250, 208);
+ position: absolute;
+ left: 100%;
+ width: 200px;
+ height: 200px;
+ }
+</style>
+</head>
+<body>
+<div id="parent">
+ <div id="child"></div>
+</div>
+</body>
+<script>
+const test = async_test("ParentWithOverflowVisibleAndNotVisible");
+const child = document.getElementById("child");
+const observer = new IntersectionObserver((entries) => {
+ test.step(() => {
+ assert_true(entries[0].isIntersecting);
+ assert_equals(entries[0].intersectionRatio, 1.0);
+ assert_equals(entries[0].intersectionRect.height, 200);
+ assert_equals(entries[0].intersectionRect.width, 200);
+ });
+ test.done();
+});
+observer.observe(child);
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/intersection-observer/v2/position-relative.html b/testing/web-platform/tests/intersection-observer/v2/position-relative.html
new file mode 100644
index 0000000000..4cdc429570
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/position-relative.html
@@ -0,0 +1,49 @@
+<!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;
+}
+.relpos {
+ position: relative;
+}
+</style>
+
+<div id="target" class="relpos">
+ <div class="relpos">
+ <img border="0" width="100" height="100" src=""/>
+ </div>
+</div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ assert_true(!!target, "target exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing a position:relative div containing a position:relative child");
+
+function step0() {
+ assert_equals(entries.length, 1, "First notification.");
+ assert_true(entries[0].isVisible, "Target is visible.");
+}
+</script>
+
diff --git a/testing/web-platform/tests/intersection-observer/v2/scaled-target.html b/testing/web-platform/tests/intersection-observer/v2/scaled-target.html
new file mode 100644
index 0000000000..f48f0792d0
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/scaled-target.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+ position: absolute;
+ top: 0;
+ left: 200px;
+}
+#iframe {
+ width: 100px;
+ height: 100px;
+ border: 0;
+ margin-bottom: 10px;
+}
+#occluder {
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ position: relative;
+}
+</style>
+
+<iframe id="iframe" src="../resources/scaled-target-subframe.html"></iframe>
+<div id="occluder"></div>
+
+<script>
+async_test(function(t) {
+ let iframe = document.getElementById("iframe");
+
+ function step0(event) {
+ assert_equals(event.data, "");
+ }
+
+ function step1(event) {
+ iframe.style.transform = "scale(2)";
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([true]));
+ }
+
+ function step2(event) {
+ assert_equals(JSON.stringify(event.data),
+ JSON.stringify([false]));
+ }
+
+ let steps = [step0, step1, step2];
+
+ window.addEventListener("message", event => {
+ if (steps.length) {
+ t.step(steps.shift(), t, event);
+ waitForFrame(t, () => {
+ iframe.contentWindow.postMessage("", "*")
+ });
+ } else {
+ t.done();
+ }
+ });
+
+}, "IntersectionObserver V2 test with scale applied to target.");
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/simple-effects.html b/testing/web-platform/tests/intersection-observer/v2/simple-effects.html
new file mode 100644
index 0000000000..baf32203c7
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/simple-effects.html
@@ -0,0 +1,72 @@
+<!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;
+}
+#effects {
+ opacity: 1;
+ filter: none;
+}
+</style>
+
+<div id="effects">
+ <div id="target"></div>
+</div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var effects;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ effects = document.getElementById("effects");
+ assert_true(!!target, "target exists");
+ assert_true(!!effects, "effects exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with a non-zero opacity ancestor.", delay);
+
+function step0() {
+ effects.style.opacity = "0.99";
+ runTestCycle(step1, "effects.style.opacity = 0.99", delay);
+ checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+
+function step1() {
+ effects.style.opacity = "1";
+ runTestCycle(step2, "effects.style.opacity = 1", delay);
+ checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+}
+
+function step2() {
+ effects.style.filter = "grayscale(50%)";
+ runTestCycle(step3, "effects.style.filter = grayscale(50%)", delay);
+ checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+
+function step3() {
+ checkLastEntry(entries, 3, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html b/testing/web-platform/tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
new file mode 100644
index 0000000000..588ec2abd6
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
@@ -0,0 +1,71 @@
+<!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>
+<svg id="svg" style="display: block">
+ <foreignObject>
+ <div id="occluder"></div>
+ </foreignObject>
+</svg>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
+
+function step0() {
+ svg.style.marginTop = "-10px";
+ runTestCycle(step1, "svg.style.marginTop = '-10px'", delay);
+ checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+
+function step1() {
+ // Occluding elements with opacity=0 should not affect target visibility.
+ svg.style.opacity = "0";
+ runTestCycle(step2, "occluder.style.opacity = 0", delay);
+ checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+}
+
+function step2() {
+ checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/simple-occlusion.html b/testing/web-platform/tests/intersection-observer/v2/simple-occlusion.html
new file mode 100644
index 0000000000..f3ce518b34
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/simple-occlusion.html
@@ -0,0 +1,67 @@
+<!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>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
+
+function step0() {
+ occluder.style.marginTop = "-10px";
+ runTestCycle(step1, "occluder.style.marginTop = '-10px'", delay);
+ checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+
+function step1() {
+ // Occluding elements with opacity=0 should not affect target visibility.
+ occluder.style.opacity = "0";
+ runTestCycle(step2, "occluder.style.opacity = 0", delay);
+ checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+}
+
+function step2() {
+ checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/text-editor-occlusion.html b/testing/web-platform/tests/intersection-observer/v2/text-editor-occlusion.html
new file mode 100644
index 0000000000..2edb7bbbe6
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/text-editor-occlusion.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<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;
+}
+.testdiv {
+ font-size: 24px;
+}
+</style>
+
+<div class="testdiv">Target: <input id="target" type="text"></input></div>
+<div class="testdiv" id="occluder">This is the occluder.</div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("occluder");
+ assert_true(!!target, "target exists");
+ assert_true(!!occluder, "occluder exists");
+ var 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
+
+function step0() {
+ occluder.style.marginTop = "-10px";
+ runTestCycle(step1, "occluder.style.marginTop = '-10px'", delay);
+ assert_equals(entries.length, 1);
+ assert_true(entries[0].isVisible);
+}
+
+function step1() {
+ // Occluding elements with opacity=0 should not affect target visibility.
+ occluder.style.opacity = "0";
+ runTestCycle(step2, "occluder.style.opacity = 0", delay);
+ assert_equals(entries.length, 2);
+ assert_false(entries[1].isVisible);
+}
+
+function step2() {
+ assert_equals(entries.length, 3);
+ assert_true(entries[2].isVisible);
+}
+</script>
diff --git a/testing/web-platform/tests/intersection-observer/v2/text-shadow.html b/testing/web-platform/tests/intersection-observer/v2/text-shadow.html
new file mode 100644
index 0000000000..cdfc1a2d2a
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/v2/text-shadow.html
@@ -0,0 +1,70 @@
+<!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;
+}
+iframe {
+ width: 100px;
+ height: 100px;
+ border: 0;
+}
+#text-shadow {
+ display: inline-block;
+ font-size: 144px;
+ font-weight: 1000;
+ color: rgba(0, 0, 0, 0);
+ text-shadow: -100px 0 0 rgba(255, 0, 0, .7);
+}
+</style>
+
+<iframe id=target srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe><div id=text-shadow>O</div>
+
+<script>
+var delay = 100;
+var entries = [];
+var target;
+var occluder;
+
+runTestCycle(function() {
+ target = document.getElementById("target");
+ occluder = document.getElementById("text-shadow");
+ 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.");
+ runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing an iframe element.", delay);
+
+function step0() {
+ occluder.style.textShadow = "none";
+ runTestCycle(step1, 'occluder.style.textShadow = "none"', delay);
+ assert_equals(entries.length, 1, "Initial notification.");
+ assert_equals(entries[0].isVisible, false, "Initially occluded.");
+}
+
+function step1() {
+ occluder.style.textShadow = "";
+ runTestCycle(step2, 'occluder.style.textShadow = ""', delay);
+ assert_equals(entries.length, 2, "Notification after removing text shadow.");
+ assert_equals(entries[1].isVisible, true, "Visible when text shadow removed.");
+}
+
+function step2() {
+ assert_equals(entries.length, 3, "Notification after re-adding text shadow.");
+ assert_equals(entries[2].isVisible, false, "Occluded when text shadow re-added.");
+}
+</script>