chromium/chrome/test/data/android/view_transition_util.js

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

let transition = null;

addEventListener('pagereveal', e => {
  if (e.viewTransition) {
    _transitionDidStart(e.viewTransition);
  }
});

// Allow tests to control when the transition starts. Tests call
// startTransitionAnimation() to complete the author DOM callback and allow the
// view-transition to start the animation.
let startTransitionAnimation = null;
let startPromise =
    new Promise(resolve => {startTransitionAnimation = resolve;});

// Allow tests to wait until the snapshot has been taken and is ready to start
// transitioning. Tests use readyToStartPromise to wait until the the author
// updateDOM callback has been invoked.
let readyToStartResolve = null;
let readyToStartPromise =
    new Promise(resolve => {readyToStartResolve = resolve;});

// Individual test files set this to perform the DOM update to the new
// transition state.
let updateDOM = null;

// Sets the animation time to just before the end (not the end itself) to
// prevent finishing the animation. Since the animations have steps timing
// function the state is equivalent to the end state itself.
function animateToEndState() {
  if (transition == null)
    throw new Error('Transition was already finished or never started.');

  for (const anim of document.getAnimations())
    anim.currentTime = anim.effect.getTiming().duration - 1;
}

// Finishes animations, and thus the view transition.
function finishAnimations() {
  if (transition == null)
    throw new Error('Transition was already finished or never started.');

  for (const anim of document.getAnimations())
    anim.finish();
}

// Creates a view transition. The transition will call the test's defined
// updateDOM function to mutate the DOM into the new state and resolve the
// readyToStartPromise when the DOM has been updated. The animation won't start
// until the test calls startTransitionAnimation().
function createTransition() {
  if (transition != null)
    throw new Error('In-progress transition already exists.');
  if (updateDOM == null)
    throw new Error('Test must set an updateDOM function');

  let t = document.startViewTransition(() => {
    updateDOM();

    readyToStartResolve();

    return startPromise;
  });

  _transitionDidStart(t);
}

// Lets the harness know about an active transition. This will cause its
// animations to be initially paused.
function _transitionDidStart(t) {
  transition = t;

  // Initially pause the animation at the old state so the test can take a
  // screenshot. Tests can then use moveAnimationToNewState() to play the
  // animation forward to the new state.
  transition.ready.then(() => {
    for (const anim of document.getAnimations()) {
      anim.pause();
    }
  });

  transition.finished.then( () => {
    transition = null;
  });
}