<!doctype html>
<meta charset=utf-8>
<title>AnimationEffect.getComputedTiming() for CSS transitions</title>
<!-- TODO: Add a more specific link for this once it is specified. -->
<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.js"></script>
<style>

.animated-div {
  margin-left: 100px;
}

</style>
<div id="log"></div>
<script>

'use strict';


// --------------------
// delay
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().delay, 0, 'Initial value of delay');
}, 'delay of a new tranisition');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().delay, 10000,
                'Initial value of delay');
}, 'Positive delay of a new transition');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s -5s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().delay, -5000,
                'Initial value of delay');
}, 'Negative delay of a new transition');


// --------------------
// endDelay
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().endDelay, 0,
                'Initial value of endDelay');
}, 'endDelay of a new transition');


// --------------------
// fill
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().fill, 'backwards', 'Fill backwards');
}, 'fill of a new transition');


// --------------------
// iterationStart
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().iterationStart, 0,
                'Initial value of iterationStart');
}, 'iterationStart of a new transition');


// --------------------
// iterations
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().iterations, 1,
                'Initial value of iterations');
}, 'iterations of a new transition');


// --------------------
// duration
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().duration, 10000,
                'Initial value of duration');
}, 'duration of a new transition');


// --------------------
// direction
// --------------------

test(t => {
  const div = addDiv(t, { class : 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().direction, 'normal',
                'Initial value of direction');
}, 'direction of a new transition');


// --------------------
// easing
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().easing, 'ease',
                'Initial value of easing');
}, 'easing of a new transition');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s steps(4)';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().easing, 'steps(4)',
                'Initial value of easing');
}, 'non-default easing of a new transition');


// ------------------------------
// endTime
// = max(start delay + active duration + end delay, 0)
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 100s -5s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  const answer = 100000 - 5000; // ms
  assert_equals(effect.getComputedTiming().endTime, answer,
                'Initial value of endTime');
}, 'endTime of a new transition');


// --------------------
// activeDuration
// = iteration duration * iteration count(==1)
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 100s -5s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().activeDuration, 100000,
                'Initial value of activeDuration');
}, 'activeDuration of a new transition');


// --------------------
// localTime
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 100s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().localTime, 0,
                'Initial value of localTime');
}, 'localTime of a new transition');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 100s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const anim = div.getAnimations()[0];
  anim.currentTime = 5000;
  assert_equals(anim.effect.getComputedTiming().localTime, anim.currentTime,
                'current localTime after setting currentTime');
}, 'localTime is always equal to currentTime');

promise_test(async t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 100s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const anim = div.getAnimations()[0];
  anim.playbackRate = 2; // 2 times faster

  await anim.ready;

  assert_equals(anim.effect.getComputedTiming().localTime, anim.currentTime,
                'localTime is equal to currentTime');
  await waitForFrame();

  assert_equals(anim.effect.getComputedTiming().localTime, anim.currentTime,
                'localTime is equal to currentTime');
}, 'localTime reflects playbackRate immediately');


// --------------------
// progress
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10.5s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().progress, 0.0,
                'Initial value of progress');
}, 'progress of a new transition');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10.5s 2s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().progress, 0.0,
                'Initial value of progress');
}, 'progress of a new transition with positive delay in before phase');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10.5s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const anim = div.getAnimations()[0];
  anim.finish();
  assert_equals(anim.effect.getComputedTiming().progress, null,
                'finished progress');
}, 'progress of a finished transition');


// --------------------
// currentIteration
// --------------------

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().currentIteration, 0,
                'Initial value of currentIteration');
}, 'currentIteration of a new transition');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s 2s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const effect = div.getAnimations()[0].effect;
  assert_equals(effect.getComputedTiming().currentIteration, 0,
                'Initial value of currentIteration');
}, 'currentIteration of a new transition with positive delay in before phase');

test(t => {
  const div = addDiv(t, { class: 'animated-div' });
  div.style.transition = 'margin-left 10s';
  getComputedStyle(div).marginLeft;
  div.style.marginLeft = '10px';

  const anim = div.getAnimations()[0];
  anim.finish();
  assert_equals(anim.effect.getComputedTiming().currentIteration, null,
                'finished currentIteration');
}, 'currentIteration of a finished transition');

</script>
