1029 lines
32 KiB
JavaScript
1029 lines
32 KiB
JavaScript
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/**
|
|
* @fileoverview goog.events.EventTarget tester.
|
|
*/
|
|
|
|
goog.provide('goog.events.eventTargetTester');
|
|
goog.setTestOnly('goog.events.eventTargetTester');
|
|
goog.provide('goog.events.eventTargetTester.KeyType');
|
|
goog.setTestOnly('goog.events.eventTargetTester.KeyType');
|
|
goog.provide('goog.events.eventTargetTester.UnlistenReturnType');
|
|
goog.setTestOnly('goog.events.eventTargetTester.UnlistenReturnType');
|
|
|
|
goog.require('goog.array');
|
|
goog.require('goog.events');
|
|
goog.require('goog.events.Event');
|
|
goog.require('goog.events.EventTarget');
|
|
goog.require('goog.testing.asserts');
|
|
goog.require('goog.testing.recordFunction');
|
|
|
|
|
|
/**
|
|
* Setup step for the test functions. This needs to be called from the
|
|
* test setUp.
|
|
* @param {Function} listenFn Function that, given the same signature
|
|
* as goog.events.listen, will add listener to the given event
|
|
* target.
|
|
* @param {Function} unlistenFn Function that, given the same
|
|
* signature as goog.events.unlisten, will remove listener from
|
|
* the given event target.
|
|
* @param {Function} unlistenByKeyFn Function that, given 2
|
|
* parameters: src and key, will remove the corresponding
|
|
* listener.
|
|
* @param {Function} listenOnceFn Function that, given the same
|
|
* signature as goog.events.listenOnce, will add a one-time
|
|
* listener to the given event target.
|
|
* @param {Function} dispatchEventFn Function that, given the same
|
|
* signature as goog.events.dispatchEvent, will dispatch the event
|
|
* on the given event target.
|
|
* @param {Function} removeAllFn Function that, given the same
|
|
* signature as goog.events.removeAll, will remove all listeners
|
|
* according to the contract of goog.events.removeAll.
|
|
* @param {Function} getListenersFn Function that, given the same
|
|
* signature as goog.events.getListeners, will retrieve listeners.
|
|
* @param {Function} getListenerFn Function that, given the same
|
|
* signature as goog.events.getListener, will retrieve the
|
|
* listener object.
|
|
* @param {Function} hasListenerFn Function that, given the same
|
|
* signature as goog.events.hasListener, will determine whether
|
|
* listeners exist.
|
|
* @param {goog.events.eventTargetTester.KeyType} listenKeyType The
|
|
* key type returned by listen call.
|
|
* @param {goog.events.eventTargetTester.UnlistenReturnType}
|
|
* unlistenFnReturnType
|
|
* Whether we should check return value from
|
|
* unlisten call. If unlisten does not return a value, this should
|
|
* be set to false.
|
|
* @param {boolean} objectListenerSupported Whether listener of type
|
|
* Object is supported.
|
|
*/
|
|
goog.events.eventTargetTester.setUp = function(
|
|
listenFn, unlistenFn, unlistenByKeyFn, listenOnceFn,
|
|
dispatchEventFn, removeAllFn,
|
|
getListenersFn, getListenerFn, hasListenerFn,
|
|
listenKeyType, unlistenFnReturnType, objectListenerSupported) {
|
|
listen = listenFn;
|
|
unlisten = unlistenFn;
|
|
unlistenByKey = unlistenByKeyFn;
|
|
listenOnce = listenOnceFn;
|
|
dispatchEvent = dispatchEventFn;
|
|
removeAll = removeAllFn;
|
|
getListeners = getListenersFn;
|
|
getListener = getListenerFn;
|
|
hasListener = hasListenerFn;
|
|
keyType = listenKeyType;
|
|
unlistenReturnType = unlistenFnReturnType;
|
|
objectTypeListenerSupported = objectListenerSupported;
|
|
|
|
listeners = [];
|
|
for (var i = 0; i < goog.events.eventTargetTester.MAX_; i++) {
|
|
listeners[i] = createListener();
|
|
}
|
|
|
|
eventTargets = [];
|
|
for (i = 0; i < goog.events.eventTargetTester.MAX_; i++) {
|
|
eventTargets[i] = new goog.events.EventTarget();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Teardown step for the test functions. This needs to be called from
|
|
* test teardown.
|
|
*/
|
|
goog.events.eventTargetTester.tearDown = function() {
|
|
for (var i = 0; i < goog.events.eventTargetTester.MAX_; i++) {
|
|
goog.dispose(eventTargets[i]);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* The type of key returned by key-returning functions (listen).
|
|
* @enum {number}
|
|
*/
|
|
goog.events.eventTargetTester.KeyType = {
|
|
/**
|
|
* Returns number for key.
|
|
*/
|
|
NUMBER: 0,
|
|
|
|
/**
|
|
* Returns undefined (no return value).
|
|
*/
|
|
UNDEFINED: 1
|
|
};
|
|
|
|
|
|
/**
|
|
* The type of unlisten function's return value.
|
|
*/
|
|
goog.events.eventTargetTester.UnlistenReturnType = {
|
|
/**
|
|
* Returns boolean indicating whether unlisten is successful.
|
|
*/
|
|
BOOLEAN: 0,
|
|
|
|
/**
|
|
* Returns undefind (no return value).
|
|
*/
|
|
UNDEFINED: 1
|
|
};
|
|
|
|
|
|
/**
|
|
* Expando property used on "listener" function to determine if a
|
|
* listener has already been checked. This is what allows us to
|
|
* implement assertNoOtherListenerIsCalled.
|
|
* @type {string}
|
|
*/
|
|
goog.events.eventTargetTester.ALREADY_CHECKED_PROP = '__alreadyChecked';
|
|
|
|
|
|
/**
|
|
* Expando property used on "listener" function to record the number
|
|
* of times it has been called the last time assertListenerIsCalled is
|
|
* done. This allows us to verify that it has not been called more
|
|
* times in assertNoOtherListenerIsCalled.
|
|
*/
|
|
goog.events.eventTargetTester.NUM_CALLED_PROP = '__numCalled';
|
|
|
|
|
|
/**
|
|
* The maximum number of initialized event targets (in eventTargets
|
|
* array) and listeners (in listeners array).
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
goog.events.eventTargetTester.MAX_ = 10;
|
|
|
|
|
|
/**
|
|
* Contains test event types.
|
|
* @enum {string}
|
|
*/
|
|
var EventType = {
|
|
A: goog.events.getUniqueId('a'),
|
|
B: goog.events.getUniqueId('b'),
|
|
C: goog.events.getUniqueId('c')
|
|
};
|
|
|
|
|
|
var listen, unlisten, unlistenByKey, listenOnce, dispatchEvent;
|
|
var removeAll, getListeners, getListener, hasListener;
|
|
var keyType, unlistenReturnType, objectTypeListenerSupported;
|
|
var eventTargets, listeners;
|
|
|
|
|
|
|
|
/**
|
|
* Custom event object for testing.
|
|
* @constructor
|
|
* @extends {goog.events.Event}
|
|
*/
|
|
var TestEvent = function() {
|
|
goog.base(this, EventType.A);
|
|
};
|
|
goog.inherits(TestEvent, goog.events.Event);
|
|
|
|
|
|
/**
|
|
* Creates a listener that executes the given function (optional).
|
|
* @param {!Function=} opt_listenerFn The optional function to execute.
|
|
* @return {!Function} The listener function.
|
|
*/
|
|
function createListener(opt_listenerFn) {
|
|
return goog.testing.recordFunction(opt_listenerFn);
|
|
}
|
|
|
|
|
|
/**
|
|
* Asserts that the given listener is called numCount number of times.
|
|
* @param {!Function} listener The listener to check.
|
|
* @param {number} numCount The number of times. See also the times()
|
|
* function below.
|
|
*/
|
|
function assertListenerIsCalled(listener, numCount) {
|
|
assertEquals('Listeners is not called the correct number of times.',
|
|
numCount, listener.getCallCount());
|
|
listener[goog.events.eventTargetTester.ALREADY_CHECKED_PROP] = true;
|
|
listener[goog.events.eventTargetTester.NUM_CALLED_PROP] = numCount;
|
|
}
|
|
|
|
|
|
/**
|
|
* Asserts that no other listeners, other than those verified via
|
|
* assertListenerIsCalled, have been called since the last
|
|
* resetListeners().
|
|
*/
|
|
function assertNoOtherListenerIsCalled() {
|
|
goog.array.forEach(listeners, function(l, index) {
|
|
if (!l[goog.events.eventTargetTester.ALREADY_CHECKED_PROP]) {
|
|
assertEquals(
|
|
'Listeners ' + index + ' is unexpectedly called.',
|
|
0, l.getCallCount());
|
|
} else {
|
|
assertEquals(
|
|
'Listeners ' + index + ' is unexpectedly called.',
|
|
l[goog.events.eventTargetTester.NUM_CALLED_PROP], l.getCallCount());
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Resets all listeners call count to 0.
|
|
*/
|
|
function resetListeners() {
|
|
goog.array.forEach(listeners, function(l) {
|
|
l.reset();
|
|
l[goog.events.eventTargetTester.ALREADY_CHECKED_PROP] = false;
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* The number of times a listener should have been executed. This
|
|
* exists to make assertListenerIsCalled more readable. This is used
|
|
* like so: assertListenerIsCalled(listener, times(2));
|
|
* @param {number} n The number of times a listener should have been
|
|
* executed.
|
|
* @return {number} The number n.
|
|
*/
|
|
function times(n) {
|
|
return n;
|
|
}
|
|
|
|
|
|
function testNoListener() {
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testOneListener() {
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
|
|
resetListeners();
|
|
|
|
dispatchEvent(eventTargets[0], EventType.B);
|
|
dispatchEvent(eventTargets[0], EventType.C);
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testTwoListenersOfSameType() {
|
|
var key1 = listen(eventTargets[0], EventType.A, listeners[0]);
|
|
var key2 = listen(eventTargets[0], EventType.A, listeners[1]);
|
|
|
|
if (keyType == goog.events.eventTargetTester.KeyType.NUMBER) {
|
|
assertNotEquals(key1, key2);
|
|
} else {
|
|
assertUndefined(key1);
|
|
assertUndefined(key2);
|
|
}
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testInstallingSameListeners() {
|
|
var key1 = listen(eventTargets[0], EventType.A, listeners[0]);
|
|
var key2 = listen(eventTargets[0], EventType.A, listeners[0]);
|
|
var key3 = listen(eventTargets[0], EventType.B, listeners[0]);
|
|
|
|
if (keyType == goog.events.eventTargetTester.KeyType.NUMBER) {
|
|
assertEquals(key1, key2);
|
|
assertNotEquals(key1, key3);
|
|
} else {
|
|
assertUndefined(key1);
|
|
assertUndefined(key2);
|
|
assertUndefined(key3);
|
|
}
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
|
|
dispatchEvent(eventTargets[0], EventType.B);
|
|
assertListenerIsCalled(listeners[0], times(2));
|
|
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testScope() {
|
|
listeners[0] = createListener(function(e) {
|
|
assertEquals('Wrong scope with undefined scope', eventTargets[0], this);
|
|
});
|
|
listeners[1] = createListener(function(e) {
|
|
assertEquals('Wrong scope with null scope', eventTargets[0], this);
|
|
});
|
|
var scope = {};
|
|
listeners[2] = createListener(function(e) {
|
|
assertEquals('Wrong scope with specific scope object', scope, this);
|
|
});
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1], false, null);
|
|
listen(eventTargets[0], EventType.A, listeners[2], false, scope);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
}
|
|
|
|
|
|
function testDispatchEventDoesNotThrowWithDisposedEventTarget() {
|
|
goog.dispose(eventTargets[0]);
|
|
assertTrue(dispatchEvent(eventTargets[0], EventType.A));
|
|
}
|
|
|
|
|
|
function testDispatchEventWithObjectLiteral() {
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
|
|
assertTrue(dispatchEvent(eventTargets[0], {type: EventType.A}));
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testDispatchEventWithCustomEventObject() {
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
|
|
var e = new TestEvent();
|
|
assertTrue(dispatchEvent(eventTargets[0], e));
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
|
|
var actualEvent = listeners[0].getLastCall().getArgument(0);
|
|
|
|
assertEquals(e, actualEvent);
|
|
assertEquals(eventTargets[0], actualEvent.target);
|
|
}
|
|
|
|
|
|
function testDisposingEventTargetRemovesListeners() {
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
goog.dispose(eventTargets[0]);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
/**
|
|
* Unlisten/unlistenByKey should still work after disposal. There are
|
|
* many circumstances when this is actually necessary. For example, a
|
|
* user may have listened to an event target and stored the key
|
|
* (e.g. in a goog.events.EventHandler) and only unlisten after the
|
|
* target has been disposed.
|
|
*/
|
|
function testUnlistenWorksAfterDisposal() {
|
|
var key = listen(eventTargets[0], EventType.A, listeners[0]);
|
|
goog.dispose(eventTargets[0]);
|
|
unlisten(eventTargets[0], EventType.A, listeners[1]);
|
|
if (unlistenByKey) {
|
|
unlistenByKey(eventTargets[0], key);
|
|
}
|
|
}
|
|
|
|
|
|
function testRemovingListener() {
|
|
var ret1 = unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
var ret2 = unlisten(eventTargets[0], EventType.A, listeners[1]);
|
|
var ret3 = unlisten(eventTargets[0], EventType.B, listeners[0]);
|
|
var ret4 = unlisten(eventTargets[1], EventType.A, listeners[0]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
|
|
var ret5 = unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
var ret6 = unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
|
|
assertNoOtherListenerIsCalled();
|
|
|
|
if (unlistenReturnType ==
|
|
goog.events.eventTargetTester.UnlistenReturnType.BOOLEAN) {
|
|
assertFalse(ret1);
|
|
assertFalse(ret2);
|
|
assertFalse(ret3);
|
|
assertFalse(ret4);
|
|
assertTrue(ret5);
|
|
assertFalse(ret6);
|
|
} else {
|
|
assertUndefined(ret1);
|
|
assertUndefined(ret2);
|
|
assertUndefined(ret3);
|
|
assertUndefined(ret4);
|
|
assertUndefined(ret5);
|
|
assertUndefined(ret6);
|
|
}
|
|
}
|
|
|
|
|
|
function testCapture() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
eventTargets[9].setParentEventTarget(eventTargets[0]);
|
|
|
|
var ordering = 0;
|
|
listeners[0] = createListener(
|
|
function(e) {
|
|
assertEquals(eventTargets[2], e.currentTarget);
|
|
assertEquals(eventTargets[0], e.target);
|
|
assertEquals('First capture listener is not called first', 0, ordering);
|
|
ordering++;
|
|
});
|
|
listeners[1] = createListener(
|
|
function(e) {
|
|
assertEquals(eventTargets[1], e.currentTarget);
|
|
assertEquals(eventTargets[0], e.target);
|
|
assertEquals('2nd capture listener is not called 2nd', 1, ordering);
|
|
ordering++;
|
|
});
|
|
listeners[2] = createListener(
|
|
function(e) {
|
|
assertEquals(eventTargets[0], e.currentTarget);
|
|
assertEquals(eventTargets[0], e.target);
|
|
assertEquals('3rd capture listener is not called 3rd', 2, ordering);
|
|
ordering++;
|
|
});
|
|
|
|
listen(eventTargets[2], EventType.A, listeners[0], true);
|
|
listen(eventTargets[1], EventType.A, listeners[1], true);
|
|
listen(eventTargets[0], EventType.A, listeners[2], true);
|
|
|
|
// These should not be called.
|
|
listen(eventTargets[3], EventType.A, listeners[3], true);
|
|
|
|
listen(eventTargets[0], EventType.B, listeners[4], true);
|
|
listen(eventTargets[0], EventType.C, listeners[5], true);
|
|
listen(eventTargets[1], EventType.B, listeners[6], true);
|
|
listen(eventTargets[1], EventType.C, listeners[7], true);
|
|
listen(eventTargets[2], EventType.B, listeners[8], true);
|
|
listen(eventTargets[2], EventType.C, listeners[9], true);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testBubble() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
eventTargets[9].setParentEventTarget(eventTargets[0]);
|
|
|
|
var ordering = 0;
|
|
listeners[0] = createListener(
|
|
function(e) {
|
|
assertEquals(eventTargets[0], e.currentTarget);
|
|
assertEquals(eventTargets[0], e.target);
|
|
assertEquals('First bubble listener is not called first', 0, ordering);
|
|
ordering++;
|
|
});
|
|
listeners[1] = createListener(
|
|
function(e) {
|
|
assertEquals(eventTargets[1], e.currentTarget);
|
|
assertEquals(eventTargets[0], e.target);
|
|
assertEquals('2nd bubble listener is not called 2nd', 1, ordering);
|
|
ordering++;
|
|
});
|
|
listeners[2] = createListener(
|
|
function(e) {
|
|
assertEquals(eventTargets[2], e.currentTarget);
|
|
assertEquals(eventTargets[0], e.target);
|
|
assertEquals('3rd bubble listener is not called 3rd', 2, ordering);
|
|
ordering++;
|
|
});
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[1], EventType.A, listeners[1]);
|
|
listen(eventTargets[2], EventType.A, listeners[2]);
|
|
|
|
// These should not be called.
|
|
listen(eventTargets[3], EventType.A, listeners[3]);
|
|
|
|
listen(eventTargets[0], EventType.B, listeners[4]);
|
|
listen(eventTargets[0], EventType.C, listeners[5]);
|
|
listen(eventTargets[1], EventType.B, listeners[6]);
|
|
listen(eventTargets[1], EventType.C, listeners[7]);
|
|
listen(eventTargets[2], EventType.B, listeners[8]);
|
|
listen(eventTargets[2], EventType.C, listeners[9]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testCaptureAndBubble() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
listen(eventTargets[1], EventType.A, listeners[1], true);
|
|
listen(eventTargets[2], EventType.A, listeners[2], true);
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[3]);
|
|
listen(eventTargets[1], EventType.A, listeners[4]);
|
|
listen(eventTargets[2], EventType.A, listeners[5]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
assertListenerIsCalled(listeners[3], times(1));
|
|
assertListenerIsCalled(listeners[4], times(1));
|
|
assertListenerIsCalled(listeners[5], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testPreventDefaultByReturningFalse() {
|
|
listeners[0] = createListener(function(e) { return false; });
|
|
listeners[1] = createListener(function(e) { return true; });
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
|
|
var result = dispatchEvent(eventTargets[0], EventType.A);
|
|
assertFalse(result);
|
|
}
|
|
|
|
|
|
function testPreventDefault() {
|
|
listeners[0] = createListener(function(e) { e.preventDefault(); });
|
|
listeners[1] = createListener(function(e) { return true; });
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
|
|
var result = dispatchEvent(eventTargets[0], EventType.A);
|
|
assertFalse(result);
|
|
}
|
|
|
|
|
|
function testPreventDefaultAtCapture() {
|
|
listeners[0] = createListener(function(e) { e.preventDefault(); });
|
|
listeners[1] = createListener(function(e) { return true; });
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
listen(eventTargets[0], EventType.A, listeners[1], true);
|
|
|
|
var result = dispatchEvent(eventTargets[0], EventType.A);
|
|
assertFalse(result);
|
|
}
|
|
|
|
|
|
function testStopPropagation() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
listeners[0] = createListener(function(e) { e.stopPropagation(); });
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
listen(eventTargets[1], EventType.A, listeners[2]);
|
|
listen(eventTargets[2], EventType.A, listeners[3]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testStopPropagation2() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
listeners[1] = createListener(function(e) { e.stopPropagation(); });
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
listen(eventTargets[1], EventType.A, listeners[2]);
|
|
listen(eventTargets[2], EventType.A, listeners[3]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testStopPropagation3() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
listeners[2] = createListener(function(e) { e.stopPropagation(); });
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
listen(eventTargets[1], EventType.A, listeners[2]);
|
|
listen(eventTargets[2], EventType.A, listeners[3]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testStopPropagationAtCapture() {
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
eventTargets[1].setParentEventTarget(eventTargets[2]);
|
|
|
|
listeners[0] = createListener(function(e) { e.stopPropagation(); });
|
|
listen(eventTargets[2], EventType.A, listeners[0], true);
|
|
listen(eventTargets[1], EventType.A, listeners[1], true);
|
|
listen(eventTargets[0], EventType.A, listeners[2], true);
|
|
listen(eventTargets[0], EventType.A, listeners[3]);
|
|
listen(eventTargets[1], EventType.A, listeners[4]);
|
|
listen(eventTargets[2], EventType.A, listeners[5]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testHandleEvent() {
|
|
if (!objectTypeListenerSupported) {
|
|
return;
|
|
}
|
|
|
|
var obj = {};
|
|
obj.handleEvent = goog.testing.recordFunction();
|
|
|
|
listen(eventTargets[0], EventType.A, obj);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertEquals(1, obj.handleEvent.getCallCount());
|
|
}
|
|
|
|
|
|
function testListenOnce() {
|
|
if (!listenOnce) {
|
|
return;
|
|
}
|
|
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0], true);
|
|
listenOnce(eventTargets[0], EventType.A, listeners[1]);
|
|
listenOnce(eventTargets[0], EventType.B, listeners[2]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(0));
|
|
assertNoOtherListenerIsCalled();
|
|
resetListeners();
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(0));
|
|
assertListenerIsCalled(listeners[1], times(0));
|
|
assertListenerIsCalled(listeners[2], times(0));
|
|
|
|
dispatchEvent(eventTargets[0], EventType.B);
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testUnlistenInListen() {
|
|
listeners[1] = createListener(
|
|
function(e) {
|
|
unlisten(eventTargets[0], EventType.A, listeners[1]);
|
|
unlisten(eventTargets[0], EventType.A, listeners[2]);
|
|
});
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
listen(eventTargets[0], EventType.A, listeners[2]);
|
|
listen(eventTargets[0], EventType.A, listeners[3]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(0));
|
|
assertListenerIsCalled(listeners[3], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
resetListeners();
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(0));
|
|
assertListenerIsCalled(listeners[2], times(0));
|
|
assertListenerIsCalled(listeners[3], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testUnlistenByKeyInListen() {
|
|
if (!unlistenByKey) {
|
|
return;
|
|
}
|
|
|
|
var key1, key2;
|
|
listeners[1] = createListener(
|
|
function(e) {
|
|
unlistenByKey(eventTargets[0], key1);
|
|
unlistenByKey(eventTargets[0], key2);
|
|
});
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
key1 = listen(eventTargets[0], EventType.A, listeners[1]);
|
|
key2 = listen(eventTargets[0], EventType.A, listeners[2]);
|
|
listen(eventTargets[0], EventType.A, listeners[3]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(0));
|
|
assertListenerIsCalled(listeners[3], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
resetListeners();
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(0));
|
|
assertListenerIsCalled(listeners[2], times(0));
|
|
assertListenerIsCalled(listeners[3], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testSetParentEventTarget() {
|
|
assertNull(eventTargets[0].getParentEventTarget());
|
|
|
|
eventTargets[0].setParentEventTarget(eventTargets[1]);
|
|
assertEquals(eventTargets[1], eventTargets[0].getParentEventTarget());
|
|
assertNull(eventTargets[1].getParentEventTarget());
|
|
|
|
eventTargets[0].setParentEventTarget(null);
|
|
assertNull(eventTargets[0].getParentEventTarget());
|
|
}
|
|
|
|
|
|
function testListenOnceAfterListenDoesNotChangeExistingListener() {
|
|
if (!listenOnce) {
|
|
return;
|
|
}
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(3));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testListenOnceAfterListenOnceDoesNotChangeExistingListener() {
|
|
if (!listenOnce) {
|
|
return;
|
|
}
|
|
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testListenAfterListenOnceRemoveOnceness() {
|
|
if (!listenOnce) {
|
|
return;
|
|
}
|
|
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertListenerIsCalled(listeners[0], times(3));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testUnlistenAfterListenOnce() {
|
|
if (!listenOnce) {
|
|
return;
|
|
}
|
|
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
listen(eventTargets[0], EventType.A, listeners[0]);
|
|
unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
listenOnce(eventTargets[0], EventType.A, listeners[0]);
|
|
unlisten(eventTargets[0], EventType.A, listeners[0]);
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testRemoveAllWithType() {
|
|
if (!removeAll) {
|
|
return;
|
|
}
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
listen(eventTargets[0], EventType.C, listeners[2], true);
|
|
listen(eventTargets[0], EventType.C, listeners[3]);
|
|
listen(eventTargets[0], EventType.B, listeners[4], true);
|
|
listen(eventTargets[0], EventType.B, listeners[5], true);
|
|
listen(eventTargets[0], EventType.B, listeners[6]);
|
|
listen(eventTargets[0], EventType.B, listeners[7]);
|
|
|
|
assertEquals(4, removeAll(eventTargets[0], EventType.B));
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.B);
|
|
dispatchEvent(eventTargets[0], EventType.C);
|
|
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
assertListenerIsCalled(listeners[1], times(1));
|
|
assertListenerIsCalled(listeners[2], times(1));
|
|
assertListenerIsCalled(listeners[3], times(1));
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testRemoveAll() {
|
|
if (!removeAll) {
|
|
return;
|
|
}
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
listen(eventTargets[0], EventType.A, listeners[1]);
|
|
listen(eventTargets[0], EventType.C, listeners[2], true);
|
|
listen(eventTargets[0], EventType.C, listeners[3]);
|
|
listen(eventTargets[0], EventType.B, listeners[4], true);
|
|
listen(eventTargets[0], EventType.B, listeners[5], true);
|
|
listen(eventTargets[0], EventType.B, listeners[6]);
|
|
listen(eventTargets[0], EventType.B, listeners[7]);
|
|
|
|
assertEquals(8, removeAll(eventTargets[0]));
|
|
|
|
dispatchEvent(eventTargets[0], EventType.A);
|
|
dispatchEvent(eventTargets[0], EventType.B);
|
|
dispatchEvent(eventTargets[0], EventType.C);
|
|
|
|
assertNoOtherListenerIsCalled();
|
|
}
|
|
|
|
|
|
function testGetListeners() {
|
|
if (!getListeners) {
|
|
return;
|
|
}
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
listen(eventTargets[0], EventType.A, listeners[1], true);
|
|
listen(eventTargets[0], EventType.A, listeners[2]);
|
|
listen(eventTargets[0], EventType.A, listeners[3]);
|
|
|
|
var l = getListeners(eventTargets[0], EventType.A, true);
|
|
assertEquals(2, l.length);
|
|
assertEquals(listeners[0], l[0].listener);
|
|
assertEquals(listeners[1], l[1].listener);
|
|
|
|
l = getListeners(eventTargets[0], EventType.A, false);
|
|
assertEquals(2, l.length);
|
|
assertEquals(listeners[2], l[0].listener);
|
|
assertEquals(listeners[3], l[1].listener);
|
|
|
|
l = getListeners(eventTargets[0], EventType.B, true);
|
|
assertEquals(0, l.length);
|
|
}
|
|
|
|
|
|
function testGetListener() {
|
|
if (!getListener) {
|
|
return;
|
|
}
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
|
|
assertNotNull(getListener(eventTargets[0], EventType.A, listeners[0], true));
|
|
assertNull(
|
|
getListener(eventTargets[0], EventType.A, listeners[0], true, {}));
|
|
assertNull(getListener(eventTargets[1], EventType.A, listeners[0], true));
|
|
assertNull(getListener(eventTargets[0], EventType.B, listeners[0], true));
|
|
assertNull(getListener(eventTargets[0], EventType.A, listeners[1], true));
|
|
}
|
|
|
|
|
|
function testHasListener() {
|
|
if (!hasListener) {
|
|
return;
|
|
}
|
|
|
|
assertFalse(hasListener(eventTargets[0]));
|
|
|
|
listen(eventTargets[0], EventType.A, listeners[0], true);
|
|
|
|
assertTrue(hasListener(eventTargets[0]));
|
|
assertTrue(hasListener(eventTargets[0], EventType.A));
|
|
assertTrue(hasListener(eventTargets[0], EventType.A, true));
|
|
assertTrue(hasListener(eventTargets[0], undefined, true));
|
|
assertFalse(hasListener(eventTargets[0], EventType.A, false));
|
|
assertFalse(hasListener(eventTargets[0], undefined, false));
|
|
assertFalse(hasListener(eventTargets[0], EventType.B));
|
|
assertFalse(hasListener(eventTargets[0], EventType.B, true));
|
|
assertFalse(hasListener(eventTargets[1]));
|
|
}
|
|
|
|
|
|
function testFiringEventBeforeDisposeInternalWorks() {
|
|
/**
|
|
* @extends {goog.events.EventTarget}
|
|
* @constructor
|
|
*/
|
|
var MockTarget = function() {
|
|
goog.base(this);
|
|
};
|
|
goog.inherits(MockTarget, goog.events.EventTarget);
|
|
|
|
MockTarget.prototype.disposeInternal = function() {
|
|
dispatchEvent(this, EventType.A);
|
|
goog.base(this, 'disposeInternal');
|
|
};
|
|
|
|
var t = new MockTarget();
|
|
try {
|
|
listen(t, EventType.A, listeners[0]);
|
|
t.dispose();
|
|
assertListenerIsCalled(listeners[0], times(1));
|
|
} catch (e) {
|
|
goog.dispose(t);
|
|
}
|
|
}
|
|
|
|
|
|
function testLoopDetection() {
|
|
var target = new goog.events.EventTarget();
|
|
target.setParentEventTarget(target);
|
|
|
|
try {
|
|
target.dispatchEvent('string');
|
|
fail('expected error');
|
|
} catch (e) {
|
|
assertContains('infinite', e.message);
|
|
}
|
|
}
|