<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=531585
-->
<head>
  <title>Test for Bug 531585 (transitionend event)</title>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<style type="text/css">

.bar { margin: 10px; }

#one { transition-duration: 500ms; transition-property: all; }
#two { transition: margin-left 1s; }
#three { transition: margin 0.5s 0.25s; }

#four, #five, #six, #seven::before, #seven::after {
  transition: 500ms color;
  border-color: black; /* don't derive from color */
  -moz-column-rule-color: black; /* don't derive from color */
  text-decoration-color: black; /* don't derive from color */
  outline-color: black; /* don't derive from color */
}

#four {
  /* give the reversing transition a long duration; the reversing will
     still be quick */
  transition-duration: 30s;
  transition-timing-function: cubic-bezier(0, 1, 1, 0);
}

#seven::before, #seven::after {
  content: "x";
  transition-duration: 50ms;
}
#seven[foo]::before, #seven[foo]::after { color: lime; }

</style>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=531585">Mozilla Bug 531585</a>
<p id="display">

<span id="one" style="color:blue"></span>
<span id="two"></span>
<span id="three"></span>
<span id="four" style="color: blue"></span>
<span id="five" style="color: blue"></span>
<span id="six" style="color: blue"></span>
<span id="seven" style="color: blue"></span>

</p>
<pre id="test">
<script type="application/javascript">

/** Test for Bug 531585 (transitionend event) **/

SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
var gTestCount = 0;
function started_test() { ++gTestCount; }
function finished_test() { if (--gTestCount == 0) { SimpleTest.finish(); } }

function $(id) { return document.getElementById(id); }
function cs(id) { return getComputedStyle($(id), ""); }

var got_one_root = false;
var got_one_target = false;
var got_two_target = false;
var got_three_top = false;
var got_three_right = false;
var got_three_bottom = false;
var got_three_left = false;
var got_four_root = false;
var got_body = false;
var did_stops = false;
var got_before = false;
var got_after = false;

document.documentElement.addEventListener("transitionend",
  function(event) {
    if (event.target == $("one")) {
      ok(!got_one_root, "transitionend on one on root");
      is(event.propertyName, "border-right-color",
         "propertyName for transitionend on one");
      is(event.elapsedTime, 0.5,
         "elapsedTime for transitionend on one");
      is(cs("one").borderRightColor, "rgb(0, 255, 0)",
         "computed style for transitionend on one");
      got_one_root = true;
      finished_test();
    } else if (event.target == $("four")) {
      ok(!got_four_root, "transitionend on four on root");
      is(event.propertyName, "color",
         "propertyName for transitionend on four");
      // Reported time should (really?) be shortened by reversing.
      ok(event.elapsedTime < 30,
         "elapsedTime for transitionend on four");
      is(cs("four").color, "rgb(0, 0, 255)",
         "computed style for transitionend on four (end of reverse transition)");
      got_four_root = true;
      finished_test();
    } else if (event.target == document.body) {
      // A synthesized event.
      ok(!got_body, "transitionend on body on root");
      is(event.propertyName, "some-unknown-prop",
         "propertyName for transitionend on body");
      // Reported time should (really?) be shortened by reversing.
      is(event.elapsedTime, 0.5,
         "elapsedTime for transitionend on body");
      got_body = true;
      finished_test();
    } else if (event.target == $("seven")) {
      if (!got_before) {
        got_before = true;
        is(event.pseudoElement, "::before");
      } else {
        ok(!got_after, "transitionend on #seven::after");
        got_after = true;
        is(event.pseudoElement, "::after");
      }
      is(event.propertyName, "color");
      is(event.isTrusted, true);
      finished_test();
    } else {
      if (!did_stops &&
          (event.target == $("five") || event.target == $("six"))) {
        todo(false,
             "timeout to stop transitions firing later than it should be");
        return;
      }
      ok(false,
         "unexpected event on " + event.target.nodeName +
         " element with id '" + event.target.id + "' " +
         "elapsedTime=" + event.elapsedTime +
         " propertyName='" + event.propertyName + "'");
    }
  }, false);

$("one").addEventListener("transitionend",
  function(event) {
    is(event.propertyName, "color", "unexpected " +
       "property name for transitionend on one on target");
    ok(!got_one_target,
        "transitionend on one on target (color)");
    got_one_target = true;
    event.stopPropagation();
    is(event.elapsedTime, 0.5,
       "elapsedTime for transitionend on one");
    is(cs("one").getPropertyValue(event.propertyName), "rgb(0, 255, 0)",
       "computed style of " + event.propertyName + " for transitionend on one");
    finished_test();
  }, false);

started_test(); // color on #one
$("one").style.color = "lime";


$("two").addEventListener("transitionend",
  function(event) {
    event.stopPropagation();

    ok(!got_two_target, "transitionend on two on target");
    is(event.propertyName, "margin-left",
       "propertyName for transitionend on two");
    is(event.elapsedTime, 1,
       "elapsedTime for transitionend on two");
    is(event.bubbles, true,
       "transitionend events should bubble");
    is(event.cancelable, false,
       "transitionend events should not be cancelable");
    is(cs("two").marginLeft, "10px",
       "computed style for transitionend on two");
    got_two_target = true;
    finished_test();
  }, false);

started_test(); // #two
$("two").className = "bar";

$("three").addEventListener("transitionend",
  function(event) {
    event.stopPropagation();

    switch (event.propertyName) {
      case "margin-top":
        ok(!got_three_top, "should only get margin-top once");
        got_three_top = true;
        break;
      case "margin-right":
        ok(!got_three_right, "should only get margin-right once");
        got_three_right = true;
        break;
      case "margin-bottom":
        ok(!got_three_bottom, "should only get margin-bottom once");
        got_three_bottom = true;
        break;
      case "margin-left":
        ok(!got_three_left, "should only get margin-left once");
        got_three_left = true;
        break;
      default:
        ok(false, "unexpected property name " + event.propertyName +
                  " for transitionend on three");
    }
    is(event.elapsedTime, 0.5,
       "elapsedTime for transitionend on three");
    is(cs("three").getPropertyValue(event.propertyName), "10px",
       "computed style for transitionend on three");
    finished_test();
  }, true);

started_test(); // margin-top on #three
started_test(); // margin-right on #three
started_test(); // margin-bottom on #three
started_test(); // margin-left on #three
$("three").className = "bar";

// We reverse the transition on four, and we should only get an event
// at the end of the second transition.
started_test(); // #four (listener on root)
$("four").style.color = "lime";

// We cancel the transition on five by changing 'transition-property',
// and should thus get no event.
$("five").style.color = "lime";

// We cancel the transition on six by changing 'transition-duration' and
// then changing the value, so we should get no event.
$("six").style.color = "lime";

started_test(); // #seven::before (listener on root)
started_test(); // #seven::after (listener on root)
$("seven").setAttribute("foo", "bar");

setTimeout(function() {
             if (cs("five") != "rgb(0, 255, 0)" &&
                 cs("six") != "rgb(0, 255, 0)") {
               // The transition hasn't finished already.
               did_stops = true;
             }
             $("five").style.transitionProperty = "margin-left";
             $("six").style.transitionDuration = "0s";
             $("six").style.transitionDelay = "0s";
             $("six").style.color = "blue";
           }, 100);
function poll_start_reversal() {
  if (cs("four").color != "rgb(0, 0, 255)") {
    // The forward transition has started.
    $("four").style.color = "blue";
  } else {
    // The forward transition has not started yet.
    setTimeout(poll_start_reversal, 20);
  }
}
setTimeout(poll_start_reversal, 200);

// And make our own event to dispatch to the body.
started_test(); // synthesized event to body (listener on root)

var e = new TransitionEvent("transitionend",
                            {
                              bubbles: true,
                              cancelable: true,
                              propertyName: "some-unknown-prop",
                              elapsedTime: 0.5,
                              pseudoElement: "pseudo"
                            });
is(e.bubbles, true);
is(e.cancelable, true);
is(e.propertyName, "some-unknown-prop");
is(e.elapsedTime, 0.5);
is(e.pseudoElement, "pseudo");
is(e.isTrusted, false)

document.body.dispatchEvent(e);

</script>
</pre>
</body>
</html>