blob: 8c642ec5176bb1e32c959c22c3ee8647f49cd276 [file] [log] [blame]
// Copyright 2008 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.
goog.provide('goog.testing.eventsTest');
goog.setTestOnly('goog.testing.eventsTest');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.math.Coordinate');
goog.require('goog.string');
goog.require('goog.style');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.events');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.recordFunction');
goog.require('goog.userAgent');
var firedEventTypes;
var firedEventCoordinates;
var firedScreenCoordinates;
var firedShiftKeys;
var firedKeyCodes;
var root;
var log;
var input;
var testButton;
var parentEl;
var childEl;
var coordinate = new goog.math.Coordinate(123, 456);
var stubs = new goog.testing.PropertyReplacer();
var eventCount;
function setUpPage() {
root = goog.dom.getElement('root');
log = goog.dom.getElement('log');
input = goog.dom.getElement('input');
testButton = goog.dom.getElement('testButton');
parentEl = goog.dom.getElement('parentEl');
childEl = goog.dom.getElement('childEl');
}
function setUp() {
stubs.reset();
goog.events.removeAll(root);
goog.events.removeAll(log);
goog.events.removeAll(input);
goog.events.removeAll(testButton);
goog.events.removeAll(parentEl);
goog.events.removeAll(childEl);
root.innerHTML = '';
firedEventTypes = [];
firedEventCoordinates = [];
firedScreenCoordinates = [];
firedShiftKeys = [];
firedKeyCodes = [];
for (var key in goog.events.EventType) {
goog.events.listen(root, goog.events.EventType[key], function(e) {
firedEventTypes.push(e.type);
var coord = new goog.math.Coordinate(e.clientX, e.clientY);
firedEventCoordinates.push(coord);
firedScreenCoordinates.push(
new goog.math.Coordinate(e.screenX, e.screenY));
firedShiftKeys.push(!!e.shiftKey);
firedKeyCodes.push(e.keyCode);
});
}
eventCount = {
parentBubble: 0,
parentCapture: 0,
childCapture: 0,
childBubble: 0
};
// Event listeners for the capture/bubble test.
goog.events.listen(parentEl, goog.events.EventType.CLICK,
function(e) {
eventCount.parentCapture++;
assertEquals(parentEl, e.currentTarget);
assertEquals(childEl, e.target);
}, true);
goog.events.listen(childEl, goog.events.EventType.CLICK,
function(e) {
eventCount.childCapture++;
assertEquals(childEl, e.currentTarget);
assertEquals(childEl, e.target);
}, true);
goog.events.listen(childEl, goog.events.EventType.CLICK,
function(e) {
eventCount.childBubble++;
assertEquals(childEl, e.currentTarget);
assertEquals(childEl, e.target);
});
goog.events.listen(parentEl, goog.events.EventType.CLICK,
function(e) {
eventCount.parentBubble++;
assertEquals(parentEl, e.currentTarget);
assertEquals(childEl, e.target);
});
}
function tearDownPage() {
for (var key in goog.events.EventType) {
var type = goog.events.EventType[key];
if (type == 'mousemove' || type == 'mouseout' || type == 'mouseover') {
continue;
}
goog.dom.appendChild(input,
goog.dom.createDom('label', null,
goog.dom.createDom('input',
{'id': type, 'type': 'checkbox'}),
type,
goog.dom.createDom('br')));
goog.events.listen(testButton, type, function(e) {
if (goog.dom.getElement(e.type).checked) {
e.preventDefault();
}
log.innerHTML += goog.string.subs('<br />%s (%s, %s)',
e.type, e.clientX, e.clientY);
});
}
}
function testMouseOver() {
goog.testing.events.fireMouseOverEvent(root, null);
goog.testing.events.fireMouseOverEvent(root, null, coordinate);
assertEventTypes(['mouseover', 'mouseover']);
assertCoordinates([goog.style.getClientPosition(root), coordinate]);
}
function testMouseOut() {
goog.testing.events.fireMouseOutEvent(root, null);
goog.testing.events.fireMouseOutEvent(root, null, coordinate);
assertEventTypes(['mouseout', 'mouseout']);
assertCoordinates([goog.style.getClientPosition(root), coordinate]);
}
function testFocus() {
goog.testing.events.fireFocusEvent(root);
assertEventTypes(['focus']);
}
function testBlur() {
goog.testing.events.fireBlurEvent(root);
assertEventTypes(['blur']);
}
function testClickSequence() {
assertTrue(goog.testing.events.fireClickSequence(root));
assertEventTypes(['mousedown', 'mouseup', 'click']);
var rootPosition = goog.style.getClientPosition(root);
assertCoordinates([rootPosition, rootPosition, rootPosition]);
}
function testClickSequenceWithCoordinate() {
assertTrue(goog.testing.events.fireClickSequence(root, null, coordinate));
assertCoordinates([coordinate, coordinate, coordinate]);
assertArrayEquals([false, false, false], firedShiftKeys);
}
function testTouchStart() {
goog.testing.events.fireTouchStartEvent(root);
goog.testing.events.fireTouchStartEvent(root, coordinate);
assertEventTypes(['touchstart', 'touchstart']);
assertCoordinates([goog.style.getClientPosition(root), coordinate]);
}
function testTouchMove() {
goog.testing.events.fireTouchMoveEvent(root);
goog.testing.events.fireTouchMoveEvent(root, coordinate, {touches: []});
assertEventTypes(['touchmove', 'touchmove']);
assertCoordinates([goog.style.getClientPosition(root), coordinate]);
}
function testTouchEnd() {
goog.testing.events.fireTouchEndEvent(root);
goog.testing.events.fireTouchEndEvent(root, coordinate);
assertEventTypes(['touchend', 'touchend']);
assertCoordinates([goog.style.getClientPosition(root), coordinate]);
}
function testTouchSequence() {
assertTrue(goog.testing.events.fireTouchSequence(root));
assertEventTypes(['touchstart', 'touchend']);
var rootPosition = goog.style.getClientPosition(root);
assertCoordinates([rootPosition, rootPosition]);
}
function testTouchSequenceWithCoordinate() {
assertTrue(goog.testing.events.fireTouchSequence(root, coordinate));
assertCoordinates([coordinate, coordinate]);
}
function testClickSequenceWithEventProperty() {
assertTrue(goog.testing.events.fireClickSequence(
root, null, undefined, { shiftKey: true }));
assertArrayEquals([true, true, true], firedShiftKeys);
}
function testClickSequenceCancellingMousedown() {
preventDefaultEventType('mousedown');
assertFalse(goog.testing.events.fireClickSequence(root));
assertEventTypes(['mousedown', 'mouseup', 'click']);
}
function testClickSequenceCancellingMousedownWithCoordinate() {
preventDefaultEventType('mousedown');
assertFalse(goog.testing.events.fireClickSequence(root, null, coordinate));
assertCoordinates([coordinate, coordinate, coordinate]);
}
function testClickSequenceCancellingMouseup() {
preventDefaultEventType('mouseup');
assertFalse(goog.testing.events.fireClickSequence(root));
assertEventTypes(['mousedown', 'mouseup', 'click']);
}
function testClickSequenceCancellingMouseupWithCoordinate() {
preventDefaultEventType('mouseup');
assertFalse(goog.testing.events.fireClickSequence(root, null, coordinate));
assertCoordinates([coordinate, coordinate, coordinate]);
}
function testClickSequenceCancellingClick() {
preventDefaultEventType('click');
assertFalse(goog.testing.events.fireClickSequence(root));
assertEventTypes(['mousedown', 'mouseup', 'click']);
}
function testClickSequenceCancellingClickWithCoordinate() {
preventDefaultEventType('click');
assertFalse(goog.testing.events.fireClickSequence(root, null, coordinate));
assertCoordinates([coordinate, coordinate, coordinate]);
}
// For a double click, IE fires selectstart instead of the second mousedown,
// but we don't simulate selectstart. Also, IE doesn't fire the second click.
var DBLCLICK_SEQ = (goog.userAgent.IE ?
['mousedown',
'mouseup',
'click',
'mouseup',
'dblclick'] :
['mousedown',
'mouseup',
'click',
'mousedown',
'mouseup',
'click',
'dblclick']);
var DBLCLICK_SEQ_COORDS = goog.array.repeat(coordinate, DBLCLICK_SEQ.length);
function testDoubleClickSequence() {
assertTrue(goog.testing.events.fireDoubleClickSequence(root));
assertEventTypes(DBLCLICK_SEQ);
}
function testDoubleClickSequenceWithCoordinate() {
assertTrue(goog.testing.events.fireDoubleClickSequence(root, coordinate));
assertCoordinates(DBLCLICK_SEQ_COORDS);
}
function testDoubleClickSequenceCancellingMousedown() {
preventDefaultEventType('mousedown');
assertFalse(goog.testing.events.fireDoubleClickSequence(root));
assertEventTypes(DBLCLICK_SEQ);
}
function testDoubleClickSequenceCancellingMousedownWithCoordinate() {
preventDefaultEventType('mousedown');
assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
assertCoordinates(DBLCLICK_SEQ_COORDS);
}
function testDoubleClickSequenceCancellingMouseup() {
preventDefaultEventType('mouseup');
assertFalse(goog.testing.events.fireDoubleClickSequence(root));
assertEventTypes(DBLCLICK_SEQ);
}
function testDoubleClickSequenceCancellingMouseupWithCoordinate() {
preventDefaultEventType('mouseup');
assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
assertCoordinates(DBLCLICK_SEQ_COORDS);
}
function testDoubleClickSequenceCancellingClick() {
preventDefaultEventType('click');
assertFalse(goog.testing.events.fireDoubleClickSequence(root));
assertEventTypes(DBLCLICK_SEQ);
}
function testDoubleClickSequenceCancellingClickWithCoordinate() {
preventDefaultEventType('click');
assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
assertCoordinates(DBLCLICK_SEQ_COORDS);
}
function testDoubleClickSequenceCancellingDoubleClick() {
preventDefaultEventType('dblclick');
assertFalse(goog.testing.events.fireDoubleClickSequence(root));
assertEventTypes(DBLCLICK_SEQ);
}
function testDoubleClickSequenceCancellingDoubleClickWithCoordinate() {
preventDefaultEventType('dblclick');
assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
assertCoordinates(DBLCLICK_SEQ_COORDS);
}
function testKeySequence() {
assertTrue(goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.ZERO));
assertEventTypes(['keydown', 'keypress', 'keyup']);
}
function testKeySequenceCancellingKeydown() {
preventDefaultEventType('keydown');
assertFalse(goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.ZERO));
assertEventTypes(['keydown', 'keyup']);
}
function testKeySequenceCancellingKeypress() {
preventDefaultEventType('keypress');
assertFalse(goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.ZERO));
assertEventTypes(['keydown', 'keypress', 'keyup']);
}
function testKeySequenceCancellingKeyup() {
preventDefaultEventType('keyup');
assertFalse(goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.ZERO));
assertEventTypes(['keydown', 'keypress', 'keyup']);
}
function testKeySequenceWithEscapeKey() {
assertTrue(goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.ESC));
if (goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525')) {
assertEventTypes(['keydown', 'keyup']);
} else {
assertEventTypes(['keydown', 'keypress', 'keyup']);
}
}
function testKeySequenceForMacActionKeysNegative() {
stubs.set(goog.userAgent, 'GECKO', false);
goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.C, {'metaKey': true});
assertEventTypes(['keydown', 'keypress', 'keyup']);
}
function testKeySequenceForMacActionKeysPositive() {
stubs.set(goog.userAgent, 'GECKO', true);
stubs.set(goog.userAgent, 'MAC', true);
goog.testing.events.fireKeySequence(
root, goog.events.KeyCodes.C, {'metaKey': true});
assertEventTypes(['keypress', 'keyup']);
}
function testKeySequenceForOptionKeysOnMac() {
// Mac uses an option (or alt) key to type non-ASCII characters. This test
// verifies we can emulate key events sent when typing such non-ASCII
// characters.
stubs.set(goog.userAgent, 'WEBKIT', true);
stubs.set(goog.userAgent, 'MAC', true);
var optionKeyCodes = [
[0xc0, 0x00e6], // option+'
[0xbc, 0x2264], // option+,
[0xbd, 0x2013], // option+-
[0xbe, 0x2265], // option+.
[0xbf, 0x00f7], // option+/
[0x30, 0x00ba], // option+0
[0x31, 0x00a1], // option+1
[0x32, 0x2122], // option+2
[0x33, 0x00a3], // option+3
[0x34, 0x00a2], // option+4
[0x35, 0x221e], // option+5
[0x36, 0x00a7], // option+6
[0x37, 0x00b6], // option+7
[0x38, 0x2022], // option+8
[0x39, 0x00aa], // option+9
[0xba, 0x2026], // option+;
[0xbb, 0x2260], // option+=
[0xdb, 0x201c], // option+[
[0xdc, 0x00ab], // option+\
[0xdd, 0x2018], // option+]
[0x41, 0x00e5], // option+a
[0x42, 0x222b], // option+b
[0x43, 0x00e7], // option+c
[0x44, 0x2202], // option+d
[0x45, 0x00b4], // option+e
[0x46, 0x0192], // option+f
[0x47, 0x00a9], // option+g
[0x48, 0x02d9], // option+h
[0x49, 0x02c6], // option+i
[0x4a, 0x2206], // option+j
[0x4b, 0x02da], // option+k
[0x4c, 0x00ac], // option+l
[0x4d, 0x00b5], // option+m
[0x4e, 0x02dc], // option+n
[0x4f, 0x00f8], // option+o
[0x50, 0x03c0], // option+p
[0x51, 0x0153], // option+q
[0x52, 0x00ae], // option+r
[0x53, 0x00df], // option+s
[0x54, 0x2020], // option+t
[0x56, 0x221a], // option+v
[0x57, 0x2211], // option+w
[0x58, 0x2248], // option+x
[0x59, 0x00a5], // option+y
[0x5a, 0x03a9] // option+z
];
for (var i = 0; i < optionKeyCodes.length; ++i) {
firedEventTypes = [];
firedKeyCodes = [];
var keyCode = optionKeyCodes[i][0];
var keyPressKeyCode = optionKeyCodes[i][1];
goog.testing.events.fireNonAsciiKeySequence(
root, keyCode, keyPressKeyCode, {'altKey': true});
assertEventTypes(['keydown', 'keypress', 'keyup']);
assertArrayEquals([keyCode, keyPressKeyCode, keyCode], firedKeyCodes);
}
}
var CONTEXTMENU_SEQ =
goog.userAgent.WINDOWS ? ['mousedown', 'mouseup', 'contextmenu'] :
goog.userAgent.GECKO ? ['mousedown', 'contextmenu', 'mouseup'] :
goog.userAgent.WEBKIT && goog.userAgent.MAC ?
['mousedown', 'contextmenu', 'mouseup', 'click'] :
['mousedown', 'contextmenu', 'mouseup'];
function testContextMenuSequence() {
assertTrue(goog.testing.events.fireContextMenuSequence(root));
assertEventTypes(CONTEXTMENU_SEQ);
}
function testContextMenuSequenceWithCoordinate() {
assertTrue(goog.testing.events.fireContextMenuSequence(root, coordinate));
assertEventTypes(CONTEXTMENU_SEQ);
assertCoordinates(goog.array.repeat(coordinate, CONTEXTMENU_SEQ.length));
}
function testContextMenuSequenceCancellingMousedown() {
preventDefaultEventType('mousedown');
assertFalse(goog.testing.events.fireContextMenuSequence(root));
assertEventTypes(CONTEXTMENU_SEQ);
}
function testContextMenuSequenceCancellingMouseup() {
preventDefaultEventType('mouseup');
assertFalse(goog.testing.events.fireContextMenuSequence(root));
assertEventTypes(CONTEXTMENU_SEQ);
}
function testContextMenuSequenceCancellingContextMenu() {
preventDefaultEventType('contextmenu');
assertFalse(goog.testing.events.fireContextMenuSequence(root));
assertEventTypes(CONTEXTMENU_SEQ);
}
function testContextMenuSequenceFakeMacWebkit() {
stubs.set(goog.userAgent, 'WINDOWS', false);
stubs.set(goog.userAgent, 'MAC', true);
stubs.set(goog.userAgent, 'WEBKIT', true);
assertTrue(goog.testing.events.fireContextMenuSequence(root));
assertEventTypes(['mousedown', 'contextmenu', 'mouseup', 'click']);
}
function testCaptureBubble_simple() {
assertTrue(goog.testing.events.fireClickEvent(childEl));
assertObjectEquals({
parentCapture: 1,
childCapture: 1,
childBubble: 1,
parentBubble: 1
}, eventCount);
}
function testCaptureBubble_preventDefault() {
goog.events.listen(childEl, goog.events.EventType.CLICK,
function(e) {
e.preventDefault();
});
assertFalse(goog.testing.events.fireClickEvent(childEl));
assertObjectEquals({
parentCapture: 1,
childCapture: 1,
childBubble: 1,
parentBubble: 1
}, eventCount);
}
function testCaptureBubble_stopPropagationParentCapture() {
goog.events.listen(parentEl, goog.events.EventType.CLICK,
function(e) {
e.stopPropagation();
}, true /* capture */);
assertTrue(goog.testing.events.fireClickEvent(childEl));
assertObjectEquals({
parentCapture: 1,
childCapture: 0,
childBubble: 0,
parentBubble: 0
}, eventCount);
}
function testCaptureBubble_stopPropagationChildCapture() {
goog.events.listen(childEl, goog.events.EventType.CLICK,
function(e) {
e.stopPropagation();
}, true /* capture */);
assertTrue(goog.testing.events.fireClickEvent(childEl));
assertObjectEquals({
parentCapture: 1,
childCapture: 1,
childBubble: 0,
parentBubble: 0
}, eventCount);
}
function testCaptureBubble_stopPropagationChildBubble() {
goog.events.listen(childEl, goog.events.EventType.CLICK,
function(e) {
e.stopPropagation();
});
assertTrue(goog.testing.events.fireClickEvent(childEl));
assertObjectEquals({
parentCapture: 1,
childCapture: 1,
childBubble: 1,
parentBubble: 0
}, eventCount);
}
function testCaptureBubble_stopPropagationParentBubble() {
goog.events.listen(parentEl, goog.events.EventType.CLICK,
function(e) {
e.stopPropagation();
});
assertTrue(goog.testing.events.fireClickEvent(childEl));
assertObjectEquals({
parentCapture: 1,
childCapture: 1,
childBubble: 1,
parentBubble: 1
}, eventCount);
}
function testMixinListenable() {
var obj = {};
obj.doFoo = goog.testing.recordFunction();
goog.testing.events.mixinListenable(obj);
obj.doFoo();
assertEquals(1, obj.doFoo.getCallCount());
var handler = goog.testing.recordFunction();
goog.events.listen(obj, 'test', handler);
obj.dispatchEvent('test');
assertEquals(1, handler.getCallCount());
assertEquals(obj, handler.getLastCall().getArgument(0).target);
goog.events.unlisten(obj, 'test', handler);
obj.dispatchEvent('test');
assertEquals(1, handler.getCallCount());
goog.events.listen(obj, 'test', handler);
obj.dispose();
obj.dispatchEvent('test');
assertEquals(1, handler.getCallCount());
}
/**
* Assert that the list of events given was fired, in that order.
*/
function assertEventTypes(list) {
assertArrayEquals(list, firedEventTypes);
}
/**
* Assert that the list of event coordinates given was caught, in that order.
*/
function assertCoordinates(list) {
assertArrayEquals(list, firedEventCoordinates);
assertArrayEquals(list, firedScreenCoordinates);
}
/** Prevent default the event of the given type on the root element. */
function preventDefaultEventType(type) {
goog.events.listen(root, type, preventDefault);
}
function preventDefault(e) {
e.preventDefault();
}