diff options
Diffstat (limited to 'dom/events/test/test_legacy_event.html')
-rw-r--r-- | dom/events/test/test_legacy_event.html | 304 |
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> |