summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/css/timeline-scope.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/scroll-animations/css/timeline-scope.html
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/scroll-animations/css/timeline-scope.html')
-rw-r--r--testing/web-platform/tests/scroll-animations/css/timeline-scope.html322
1 files changed, 322 insertions, 0 deletions
diff --git a/testing/web-platform/tests/scroll-animations/css/timeline-scope.html b/testing/web-platform/tests/scroll-animations/css/timeline-scope.html
new file mode 100644
index 0000000000..e4e90bc03a
--- /dev/null
+++ b/testing/web-platform/tests/scroll-animations/css/timeline-scope.html
@@ -0,0 +1,322 @@
+<!DOCTYPE html>
+<title>Behavior of the timeline-scope property</title>
+<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/7759">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/web-animations/testcommon.js"></script>
+
+<main id=main></main>
+<script>
+ async function inflate(t, template) {
+ t.add_cleanup(() => main.replaceChildren());
+ return runAndWaitForFrameUpdate(() => {
+ main.append(template.content.cloneNode(true));
+ });
+ }
+
+ async function scrollTop(e, value) {
+ e.scrollTop = value;
+ await waitForNextFrame();
+ }
+</script>
+<style>
+ @keyframes anim {
+ from { width: 0px; }
+ to { width: 200px; }
+ }
+
+ .scroller {
+ overflow-y: hidden;
+ width: 200px;
+ height: 200px;
+ }
+ .scroller > .content {
+ margin: 400px 0px;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ }
+ .target {
+ background-color: coral;
+ width: 0px;
+ animation: anim auto linear;
+ animation-timeline: --t1;
+ }
+ .timeline {
+ scroll-timeline-name: --t1;
+ }
+ .scope {
+ timeline-scope: --t1;
+ }
+
+</style>
+
+<!-- Basic Behavior -->
+
+<template id=deferred_timeline>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+
+ const anim = target.getAnimations()[0];
+ await anim.ready;
+
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+ }, 'Descendant can attach to deferred timeline');
+</script>
+
+<template id=deferred_timeline_no_attachments>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_no_attachments);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '0px');
+ }, 'Deferred timeline with no attachments');
+</script>
+
+<template id=scroll_timeline_inner_interference>
+ <div class="scroller timeline">
+ <div class=content>
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, scroll_timeline_inner_interference);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+ }, 'Inner timeline does not interfere with outer timeline');
+</script>
+
+<template id=deferred_timeline_two_attachments>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ <!-- Extra attachment -->
+ <div class="timeline"></div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_two_attachments);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '0px');
+ }, 'Deferred timeline with two attachments');
+</script>
+
+<!-- Dynamic Reattachment -->
+
+<template id=deferred_timeline_reattach>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ <div class="scroller">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_reattach);
+ let scrollers = main.querySelectorAll('.scroller');
+ assert_equals(scrollers.length, 2);
+ let target = main.querySelector('.target');
+ await scrollTop(scrollers[0], 350); // 50%
+ await scrollTop(scrollers[1], 175); // 25%
+
+ // Attached to scrollers[0].
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+
+ // Reattach to scrollers[1].
+ await runAndWaitForFrameUpdate(() => {
+ scrollers[0].classList.remove('timeline');
+ scrollers[1].classList.add('timeline');
+ });
+
+ assert_equals(getComputedStyle(target).width, '50px'); // 0px => 200px, 25%
+ }, 'Dynamically re-attaching');
+</script>
+
+<template id=deferred_timeline_dynamic_detach>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_dynamic_detach);
+ let scrollers = main.querySelectorAll('.scroller');
+ assert_equals(scrollers.length, 2);
+ let target = main.querySelector('.target');
+ await scrollTop(scrollers[0], 350); // 50%
+ await scrollTop(scrollers[1], 175); // 25%
+
+ // Attached to two timelines initially:
+ assert_equals(getComputedStyle(target).width, '0px');
+
+ // Detach scrollers[1].
+ await runAndWaitForFrameUpdate(() => {
+ scrollers[1].classList.remove('timeline');
+ });
+
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+
+ // Also detach scrollers[0].
+ scrollers[0].classList.remove('timeline');
+
+ await waitForNextFrame();
+ assert_equals(getComputedStyle(target).width, '0px');
+ }, 'Dynamically detaching');
+</script>
+
+<template id=deferred_timeline_attached_removed>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_attached_removed);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+
+ let scroller_parent = scroller.parentElement;
+ scroller.remove();
+ await waitForNextFrame();
+ assert_equals(getComputedStyle(target).width, '0px');
+
+ scroller_parent.append(scroller);
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+ }, 'Removing/inserting element with attaching timeline');
+</script>
+
+<template id=deferred_timeline_attached_display_none>
+ <div class="scope">
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_attached_display_none);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+
+ scroller.style.display = 'none';
+ await waitForNextFrame();
+ assert_equals(getComputedStyle(target).width, '0px');
+
+ scroller.style.display = 'block';
+ await scrollTop(scroller, 350); // 50%
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+ }, 'Ancestor attached element becoming display:none/block');
+</script>
+
+<template id=deferred_timeline_appearing>
+ <div class=container>
+ <div class=target>Test</div>
+ <div class="scroller timeline">
+ <div class=content></div>
+ </div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_appearing);
+ let container = main.querySelector('.container');
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+
+ await scrollTop(scroller, 350); // 50%
+
+ // Not attached to any timeline initially.
+ assert_equals(getComputedStyle(target).width, '0px');
+
+ // Add the deferred timeline.
+ container.classList.add('scope');
+ await waitForNextFrame();
+ assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50%
+
+ // Remove the deferred timeline.
+ container.classList.remove('scope');
+ await waitForNextFrame();
+ assert_equals(getComputedStyle(target).width, '0px');
+ }, 'A deferred timeline appearing dynamically in the ancestor chain');
+</script>
+
+<template id=deferred_timeline_on_self>
+ <div class="scroller timeline scope">
+ <div class=content>
+ <div class=target></div>
+ </div>
+ <div class=scroller2></div>
+ </div>
+</template>
+<script>
+ promise_test(async (t) => {
+ await inflate(t, deferred_timeline_on_self);
+ let scroller = main.querySelector('.scroller');
+ let target = main.querySelector('.target');
+ await scrollTop(scroller, 525); // 75%
+
+ assert_equals(getComputedStyle(target).width, '150px'); // 0px => 200px, 75%
+
+ // A second scroll-timeline now attaches to the same root.
+ let scroller2 = main.querySelector('.scroller2');
+ scroller2.classList.add('timeline');
+ await waitForNextFrame();
+
+ // The deferred timeline produced by timeline-scope is now inactive,
+ // but it doesn't matter, because we preferred to attach
+ // to the non-deferred timeline.
+ assert_equals(getComputedStyle(target).width, '150px'); // 0px => 200px, 75%
+ }, 'Animations prefer non-deferred timelines');
+
+</script>