// 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.dom.InputType'); goog.require('goog.dom.TagName'); 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); goog.dom.removeChildren(root); 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( goog.dom.TagName.LABEL, null, goog.dom.createDom( goog.dom.TagName.INPUT, {'id': type, 'type': goog.dom.InputType.CHECKBOX}), type, goog.dom.createDom(goog.dom.TagName.BR))); goog.events.listen(testButton, type, function(e) { if (goog.dom.getElement(e.type).checked) { e.preventDefault(); } log.innerHTML += goog.string.subs('
%s (%s, %s)', e.type, e.clientX, e.clientY); }); } } function testMouseEnter() { goog.testing.events.fireMouseEnterEvent(root, null); goog.testing.events.fireMouseEnterEvent(root, null, coordinate); assertEventTypes(['mouseenter', 'mouseenter']); assertCoordinates([goog.style.getClientPosition(root), coordinate]); } function testMouseLeave() { goog.testing.events.fireMouseLeaveEvent(root, null); goog.testing.events.fireMouseLeaveEvent(root, null, coordinate); assertEventTypes(['mouseleave', 'mouseleave']); assertCoordinates([goog.style.getClientPosition(root), coordinate]); } 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 testFocusIn() { goog.testing.events.fireFocusInEvent(root); assertEventTypes([goog.events.EventType.FOCUSIN]); } 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.EDGE || (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(); }