tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit e6859b8c29f22121ebbe796970825109dc0bb282
parent c5e03584c8aa591ce00d8e94543bba2b7c301b35
Author: Vladimir Levin <vmpstr@chromium.org>
Date:   Tue, 21 Oct 2025 10:30:22 +0000

Bug 1993636 [wpt PR 55336] - VT: Implement waitUntil, a=testonly

Automatic update from web-platform-tests
VT: Implement waitUntil

This implements waitUntil by keeping a count of pending promises on
VT and only allowing it to go beyond the animating phase when this
count is 0.

Based on resolution
https://github.com/w3c/csswg-drafts/issues/9901#issuecomment-2165674531

Spec & chromestatus pending

R=nrosenthal@google.com

Bug: 346976175
Change-Id: I8f2270d532f8bb441c6a6746095eb7a535cc6833
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7028593
Commit-Queue: Vladimir Levin <vmpstr@chromium.org>
Reviewed-by: Noam Rosenthal <nrosenthal@google.com>
Cr-Commit-Position: refs/heads/main@{#1530874}

--

wpt-commits: 524f6f4e2e9ed4aee125a6cf8807029c7bd759c0
wpt-pr: 55336

Diffstat:
Atesting/web-platform/tests/css/css-view-transitions/view-transition-waituntil-animation-manipulation-ref.html | 16++++++++++++++++
Atesting/web-platform/tests/css/css-view-transitions/view-transition-waituntil-animation-manipulation.html | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/css/css-view-transitions/view-transition-waituntil-finished-promise.html | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 178 insertions(+), 0 deletions(-)

diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-waituntil-animation-manipulation-ref.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-waituntil-animation-manipulation-ref.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>View transitions: waitUntil allows animation manipulation (reference)</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<style> +body { + background: lightpink; +} +.target { + width: 100px; + height: 100px; + background: green; +} +</style> + +<div class=target></div> diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-waituntil-animation-manipulation.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-waituntil-animation-manipulation.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<title>View transitions: waitUntil allows animation manipulation</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<link rel="match" href="view-transition-waituntil-animation-manipulation-ref.html"> +<script src="/common/reftest-wait.js"></script> +<style> +:root { view-transition-name: none } + +#target { + width: 100px; + height: 100px; + background: green; + view-transition-name: target; +} + +#target.after { + background: red; +} + +::view-transition { background: lightpink; } +::view-transition-group(*) { + animation-duration: 1ms; +} +</style> + +<div id=target></div> + +<script> +failIfNot(document.startViewTransition, "Missing document.startViewTransition"); +failIfNot(ViewTransition.prototype.waitUntil, "ViewTransition.waitUntil is not available"); + +async function runTest() { + const transition = document.startViewTransition(() => target.classList.add("after")); + transition.waitUntil(new Promise(() => {})); + + transition.ready.then(async () => { + // Let the animation run to the end. + const animations = document.getAnimations(); + animations.forEach(a => { + a.currentTime = 1; + }); + + // Wait a few frames. + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + + // Now, rewind the animation and take a screenshot. + requestAnimationFrame(() => { + animations.forEach(a => { + a.play(); + a.pause(); + a.currentTime = 0; + }); + takeScreenshot(); + }); + }); +} +onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest)); +</script> diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-waituntil-finished-promise.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-waituntil-finished-promise.html @@ -0,0 +1,100 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>View Transition: waitUntil delays the finished promise</title> +<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> +#target { + width: 100px; + height: 100px; + view-transition-name: target; +} +::view-transition-group(*) { + animation-duration: 1ms; +} +</style> + +<div id=target></div> + +<script> +promise_test(async t => { + assert_implements(document.startViewTransition, "View Transitions are not supported"); + assert_implements(ViewTransition.prototype.waitUntil, "ViewTransition.waitUntil is not available"); + + let waitUntilPromiseResolve; + const waitUntilPromise = new Promise(resolve => { + waitUntilPromiseResolve = resolve; + }); + + const transition = document.startViewTransition(() => {}); + transition.waitUntil(waitUntilPromise); + + let finished = false; + transition.finished.then(() => { + finished = true; + }); + + // Wait for longer than the animation duration. + await new Promise(resolve => t.step_timeout(resolve, 100)); + + assert_false(finished, "transition.finished should not resolve before waitUntil promise"); + + waitUntilPromiseResolve(); + await transition.finished; + + assert_true(finished, "transition.finished should resolve after waitUntil promise"); +}, "View transition finished promise is delayed by waitUntil"); + +promise_test(async t => { + assert_implements(document.startViewTransition, "View Transitions are not supported"); + + let resolve1, resolve2; + const promise1 = new Promise(r => resolve1 = r); + const promise2 = new Promise(r => resolve2 = r); + + const transition = document.startViewTransition(() => {}); + transition.waitUntil(promise1); + transition.waitUntil(promise2); + + let finished = false; + transition.finished.then(() => finished = true); + + // Wait for longer than the animation duration. + await new Promise(resolve => t.step_timeout(resolve, 100)); + assert_false(finished, "transition.finished should not resolve before first promise"); + + resolve1(); + // Wait a bit to ensure the promise resolution propagates. + await new Promise(resolve => t.step_timeout(resolve, 10)); + assert_false(finished, "transition.finished should not resolve after first promise but before second"); + + resolve2(); + await transition.finished; + assert_true(finished, "transition.finished should resolve after both promises"); +}, "View transition finished promise is delayed by multiple waitUntil calls"); + +promise_test(async t => { + assert_implements(document.startViewTransition, "View Transitions are not supported"); + + let reject1; + const promise1 = new Promise((_, r) => reject1 = r); + + const transition = document.startViewTransition(() => {}); + transition.waitUntil(promise1); + + let finished = false; + transition.finished.then(() => finished = true); + + // Wait for longer than the animation duration. + await new Promise(resolve => t.step_timeout(resolve, 100)); + assert_false(finished, "transition.finished should not resolve before rejected promise"); + + reject1(new DOMException("test", "AbortError")); + await transition.finished; + assert_true(finished, "transition.finished should resolve after rejected promise"); +}, "View transition finished promise is delayed by a rejecting waitUntil promise"); +</script>