summaryrefslogtreecommitdiffstats
path: root/dom/events/test/test_legacy_event.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/events/test/test_legacy_event.html')
-rw-r--r--dom/events/test/test_legacy_event.html304
1 files changed, 304 insertions, 0 deletions
diff --git a/dom/events/test/test_legacy_event.html b/dom/events/test/test_legacy_event.html
new file mode 100644
index 000000000..d772be106
--- /dev/null
+++ b/dom/events/test/test_legacy_event.html
@@ -0,0 +1,304 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1236979
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1236979 (events that have legacy alternative versions)</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ @keyframes anim1 {
+ 0% { margin-left: 0px }
+ 100% { margin-left: 100px }
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1236979">Mozilla Bug 1236979</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1236979 **/
+
+'use strict';
+SimpleTest.waitForExplicitFinish();
+
+// Array of info-bundles about each legacy event to be tested:
+var gLegacyEventInfo = [
+ {
+ legacy_name: "webkitTransitionEnd",
+ modern_name: "transitionend",
+ trigger_event: triggerShortTransition,
+ },
+ {
+ legacy_name: "webkitAnimationStart",
+ modern_name: "animationstart",
+ trigger_event: triggerShortAnimation,
+ },
+ {
+ legacy_name: "webkitAnimationEnd",
+ modern_name: "animationend",
+ trigger_event: triggerShortAnimation,
+ },
+ {
+ legacy_name: "webkitAnimationIteration",
+ modern_name: "animationiteration",
+ trigger_event: triggerAnimationIteration,
+ }
+];
+
+// EVENT-TRIGGERING FUNCTIONS
+// --------------------------
+// This function triggers a very short (1ms long) transition, which will cause
+// events to fire for the transition ending.
+function triggerShortTransition(node) {
+ node.style.transition = "1ms color linear" ;
+ node.style.color = "purple";
+ // Flush style, so that the above assignment value actually takes effect
+ // in the computed style, so that a transition will get triggered when it
+ // changes.
+ window.getComputedStyle(node, "").color;
+ node.style.color = "teal";
+}
+
+// This function triggers a very short (1ms long) animation, which will cause
+// events to fire for the animation beginning & ending.
+function triggerShortAnimation(node) {
+ node.style.animation = "anim1 1ms linear";
+}
+
+// This function triggers a long animation with two iterations, which is
+// *nearly* at the end of its first iteration. It will hit the end of that
+// iteration (firing an event) almost immediately, 1ms in the future.
+//
+// NOTE: It's important that this animation have a *long* duration. If it were
+// short (e.g. 1ms duration), then we might jump past all its iterations in
+// a single refresh-driver tick. And if that were to happens, we'd *never* fire
+// any animationiteration events -- the CSS Animations spec says this event
+// must not be fired "...when an animationend event would fire at the same time"
+// (which would be the case in this example with a 1ms duration). So, to make
+// sure our event does fire, we use a long duration and a nearly-as-long
+// negative delay. This ensures we hit the end of the first iteration right
+// away, and that we don't risk hitting the end of the second iteration at the
+// same time.
+function triggerAnimationIteration(node) {
+ node.style.animation = "anim1 300s -299.999s linear 2";
+}
+
+// GENERAL UTILITY FUNCTIONS
+// -------------------------
+// Creates a new div and appends it as a child of the specified parentNode, or
+// (if no parent is specified) as a child of the element with ID 'display'.
+function createChildDiv(parentNode) {
+ if (!parentNode) {
+ parentNode = document.getElementById("display");
+ if (!parentNode) {
+ ok(false, "no 'display' element to append to");
+ }
+ }
+ var div = document.createElement("div");
+ parentNode.appendChild(div);
+ return div;
+}
+
+// Returns an event-handler function, which (when invoked) simply checks that
+// the event's type matches what's expected. If a callback is passed in, then
+// the event-handler will invoke that callback as well.
+function createHandlerWithTypeCheck(expectedEventType, extraHandlerLogic) {
+ var handler = function(e) {
+ is(e.type, expectedEventType,
+ "When an event handler for '" + expectedEventType + "' is invoked, " +
+ "the event's type field should be '" + expectedEventType + "'.");
+ if (extraHandlerLogic) {
+ extraHandlerLogic(e);
+ }
+ }
+ return handler;
+}
+
+// TEST FUNCTIONS
+// --------------
+// These functions expect to be passed an entry from gEventInfo, and they
+// return a Promise which performs the test & resolves when it's complete.
+// The function names all begin with "mp", which stands for "make promise".
+// So e.g. "mpTestLegacyEventSent" means "make a promise to test that the
+// legacy event is sent".
+
+// Tests that the legacy event type is sent, when only a legacy handler is
+// registered.
+function mpTestLegacyEventSent(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ // Create a node & register an event-handler for the legacy event:
+ var div = createChildDiv();
+
+ var handler = createHandlerWithTypeCheck(eventInfo.legacy_name,
+ function() {
+ // When event-handler is done, clean up & resolve:
+ div.parentNode.removeChild(div);
+ resolve();
+ });
+ div.addEventListener(eventInfo.legacy_name, handler);
+
+ // Trigger the event:
+ eventInfo.trigger_event(div);
+ }
+ );
+}
+
+// Test that the modern event type (and only the modern event type) is fired,
+// when listeners of both modern & legacy types are registered. The legacy
+// listener should not be invoked.
+function mpTestModernBeatsLegacy(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ var div = createChildDiv();
+
+ var legacyHandler = function(e) {
+ reject("Handler for legacy event '" + eventInfo.legacy_name +
+ "' should not be invoked when there's a handler registered " +
+ "for both modern & legacy event type on the same node");
+ };
+
+ var modernHandler = createHandlerWithTypeCheck(eventInfo.modern_name,
+ function() {
+ // Indicate that the test has passed (we invoked the modern handler):
+ ok(true, "Handler for modern event '" + eventInfo.modern_name +
+ "' should be invoked when there's a handler registered for " +
+ "both modern & legacy event type on the same node");
+ // When event-handler is done, clean up & resolve:
+ div.parentNode.removeChild(div);
+ resolve();
+ });
+
+ div.addEventListener(eventInfo.legacy_name, legacyHandler);
+ div.addEventListener(eventInfo.modern_name, modernHandler);
+ eventInfo.trigger_event(div);
+ }
+ );
+}
+
+// Test that an event which bubbles may fire listeners of different flavors
+// (modern vs. legacy) at each bubbling level, depending on what's registered
+// at that level.
+function mpTestDiffListenersEventBubbling(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ var grandparent = createChildDiv();
+ var parent = createChildDiv(grandparent);
+ var target = createChildDiv(parent);
+ var didEventFireOnTarget = false;
+ var didEventFireOnParent = false;
+ var eventSentToTarget;
+
+ target.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ ok(e.bubbles, "Expecting event to bubble");
+ eventSentToTarget = e;
+ didEventFireOnTarget = true;
+ }));
+
+ parent.addEventListener(eventInfo.legacy_name,
+ createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
+ is(e, eventSentToTarget,
+ "Same event object should bubble, despite difference in type");
+ didEventFireOnParent = true;
+ }));
+
+ grandparent.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ ok(didEventFireOnTarget,
+ "Event should have fired on child");
+ ok(didEventFireOnParent,
+ "Event should have fired on parent");
+ is(e, eventSentToTarget,
+ "Same event object should bubble, despite difference in type");
+ // Clean up.
+ grandparent.parentNode.removeChild(grandparent);
+ resolve();
+ }));
+
+ eventInfo.trigger_event(target);
+ }
+ );
+}
+
+// Test that an event in the capture phase may fire listeners of different
+// flavors (modern vs. legacy) at each level, depending on what's registered
+// at that level.
+function mpTestDiffListenersEventCapturing(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ var grandparent = createChildDiv();
+ var parent = createChildDiv(grandparent);
+ var target = createChildDiv(parent);
+ var didEventFireOnTarget = false;
+ var didEventFireOnParent = false;
+ var didEventFireOnGrandparent = false;
+ var eventSentToGrandparent;
+
+ grandparent.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ eventSentToGrandparent = e;
+ didEventFireOnGrandparent = true;
+ }), true);
+
+ parent.addEventListener(eventInfo.legacy_name,
+ createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
+ is(e.eventPhase, Event.CAPTURING_PHASE,
+ "event should be in capturing phase");
+ is(e, eventSentToGrandparent,
+ "Same event object should capture, despite difference in type");
+ ok(didEventFireOnGrandparent,
+ "Event should have fired on grandparent");
+ didEventFireOnParent = true;
+ }), true);
+
+ target.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ is(e.eventPhase, Event.AT_TARGET,
+ "event should be at target phase");
+ is(e, eventSentToGrandparent,
+ "Same event object should capture, despite difference in type");
+ ok(didEventFireOnParent,
+ "Event should have fired on parent");
+ // Clean up.
+ grandparent.parentNode.removeChild(grandparent);
+ resolve();
+ }), true);
+
+ eventInfo.trigger_event(target);
+ }
+ );
+}
+
+// MAIN FUNCTION: Kick off the tests.
+function main() {
+ Promise.resolve().then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestLegacyEventSent))
+ }).then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestModernBeatsLegacy));
+ }).then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventCapturing));
+ }).then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventBubbling));
+ }).then(function() {
+ SimpleTest.finish();
+ }).catch(function(reason) {
+ ok(false, "Test failed: " + reason);
+ SimpleTest.finish();
+ });
+}
+
+main();
+
+</script>
+</pre>
+</body>
+</html>