| // 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(); |
| } |