| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>touchscreen_test</title> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <script src="test_bootstrap.js"></script> |
| <script type="text/javascript"> |
| goog.require('bot.Touchscreen'); |
| goog.require('bot.action'); |
| goog.require('bot.dom'); |
| goog.require('goog.Promise'); |
| goog.require('goog.events'); |
| goog.require('goog.events.EventType'); |
| goog.require('goog.math.Coordinate'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.userAgent'); |
| </script> |
| <script type="text/javascript"> |
| var captureTarget; |
| var target; |
| var lowerTarget; |
| var innerCaptureTarget; |
| var noTouchTarget; |
| var coordsTarget; |
| |
| var touchscreen; |
| var events = []; |
| var TOUCH_EVENTS = [ |
| goog.events.EventType.TOUCHSTART, |
| goog.events.EventType.TOUCHEND, |
| goog.events.EventType.TOUCHMOVE, |
| goog.events.EventType.MOUSEMOVE, |
| goog.events.EventType.MOUSEDOWN, |
| goog.events.EventType.MOUSEOUT, |
| goog.events.EventType.MOUSEOVER, |
| goog.events.EventType.MOUSEUP, |
| goog.events.EventType.CLICK, |
| goog.events.EventType.MSPOINTERCANCEL, |
| goog.events.EventType.MSPOINTERDOWN, |
| goog.events.EventType.MSPOINTERMOVE, |
| goog.events.EventType.MSPOINTEROVER, |
| goog.events.EventType.MSPOINTEROUT, |
| goog.events.EventType.MSPOINTERUP |
| ]; |
| |
| function setUpPage() { |
| target = document.getElementById('target'); |
| lowerTarget = document.getElementById('lower'); |
| captureTarget = document.getElementById('captureTarget'); |
| innerCaptureTarget = document.getElementById('innerCaptureTarget'); |
| noTouchTarget = document.getElementById('notouch'); |
| coordsTarget = document.getElementById('coordsTarget'); |
| } |
| |
| function setUp() { |
| touchscreen = new bot.Touchscreen(); |
| events = []; |
| goog.events.removeAll(target); |
| goog.events.removeAll(lowerTarget); |
| goog.events.removeAll(captureTarget); |
| goog.events.removeAll(innerCaptureTarget); |
| goog.events.removeAll(noTouchTarget); |
| goog.events.removeAll(coordsTarget); |
| |
| goog.events.listen(target, TOUCH_EVENTS, function(e) { |
| events.push(e.type); |
| events.push(e.target); |
| if (e.type == goog.events.EventType.TOUCHSTART || |
| e.type == goog.events.EventType.TOUCHEND || |
| e.type == goog.events.EventType.TOUCHMOVE) { |
| var event = e.getBrowserEvent(); |
| events.push(event.changedTouches.length); |
| } |
| }); |
| goog.events.listen(lowerTarget, TOUCH_EVENTS, function(e) { |
| events.push(e.type); |
| events.push(e.target); |
| }); |
| goog.events.listen(captureTarget, TOUCH_EVENTS, function(e) { |
| if (e.type == goog.events.EventType.MSPOINTERDOWN) { |
| captureTarget.msSetPointerCapture(e.getBrowserEvent().pointerId); |
| } |
| events.push(e.type); |
| events.push(e.target); |
| }); |
| goog.events.listen(noTouchTarget, TOUCH_EVENTS, function(e) { |
| events.push(e.type); |
| events.push(e.target); |
| }); |
| goog.events.listen(coordsTarget, goog.events.EventType.TOUCHSTART, |
| function(e) { |
| var event = e.getBrowserEvent(); |
| if (event.changedTouches.length == 1) { |
| events.push(event.changedTouches[0].clientX); |
| events.push(event.changedTouches[0].clientY); |
| events.push(event.changedTouches[0].pageX); |
| events.push(event.changedTouches[0].pageY); |
| } |
| }); |
| } |
| |
| function msPointerDownEvents(elem) { |
| return [goog.events.EventType.MOUSEMOVE, elem].concat( |
| [goog.events.EventType.MSPOINTEROVER, elem], |
| [goog.events.EventType.MOUSEOVER, elem], |
| [goog.events.EventType.MSPOINTERDOWN, elem], |
| [goog.events.EventType.MOUSEDOWN, elem]); |
| } |
| |
| function msPointerMoveEvents(elem) { |
| return [goog.events.EventType.MSPOINTERMOVE, elem].concat( |
| [goog.events.EventType.MOUSEMOVE, elem]); |
| } |
| |
| function msPointerUpEventsWithClick(elem) { |
| return [goog.events.EventType.MSPOINTERUP, elem].concat( |
| [goog.events.EventType.MOUSEUP, elem], |
| [goog.events.EventType.CLICK, elem], |
| [goog.events.EventType.MSPOINTEROUT, elem], |
| [goog.events.EventType.MOUSEOUT, elem]); |
| } |
| |
| function msPointerUpEventsWithoutClick(elem) { |
| return [goog.events.EventType.MSPOINTERUP, elem].concat( |
| [goog.events.EventType.MOUSEUP, elem], |
| [goog.events.EventType.MSPOINTEROUT, elem], |
| [goog.events.EventType.MOUSEOUT, elem]); |
| } |
| |
| function assertEvents(var_args) { |
| var expectedEvents = goog.array.concat.apply(null, arguments); |
| assertArrayEquals(expectedEvents, events); |
| events = []; |
| } |
| |
| function testTouchScreenPress() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| assertTrue(touchscreen.isPressed()); |
| |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1]); |
| } |
| } |
| |
| function testTouchScreen2FingerPress() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, |
| new goog.math.Coordinate(0, 0), |
| new goog.math.Coordinate(10, 10)); |
| touchscreen.press(/* opt_press2 */ true); |
| assertTrue(touchscreen.isPressed()); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerDownEvents(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 2]); |
| } |
| } |
| |
| function testTouchScreen2FingerPinch() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, |
| new goog.math.Coordinate(0, 0), |
| new goog.math.Coordinate(0, 50)); |
| touchscreen.press(/* opt_press2 */ true); |
| touchscreen.move(target, |
| new goog.math.Coordinate(0, 10), |
| new goog.math.Coordinate(0, 40)); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerDownEvents(target), |
| msPointerMoveEvents(target), |
| msPointerMoveEvents(target), |
| msPointerUpEventsWithClick(target), |
| msPointerUpEventsWithClick(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 2, |
| goog.events.EventType.TOUCHMOVE, target, 2, |
| goog.events.EventType.TOUCHEND, target, 2]); |
| } |
| } |
| |
| function testTouchScreen2FingerPinchReleaseOnNoTouchElement() { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| touchscreen.move(noTouchTarget, |
| new goog.math.Coordinate(0, 0), |
| new goog.math.Coordinate(0, 50)); |
| touchscreen.press(/* opt_press2 */ true); |
| touchscreen.move(noTouchTarget, |
| new goog.math.Coordinate(0, 10), |
| new goog.math.Coordinate(0, 40)); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(noTouchTarget), |
| [goog.events.EventType.MSPOINTEROUT, noTouchTarget, |
| goog.events.EventType.MOUSEOUT, noTouchTarget, |
| goog.events.EventType.MSPOINTERCANCEL, noTouchTarget]); |
| } |
| } |
| |
| function testTouchScreen2FingerRotate() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, |
| new goog.math.Coordinate(0, 0), |
| new goog.math.Coordinate(0, 50)); |
| touchscreen.press(/* opt_press2 */ true); |
| touchscreen.move(target, new goog.math.Coordinate(10, 40)); |
| touchscreen.move(target, new goog.math.Coordinate(50, 50)); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerDownEvents(target), |
| msPointerMoveEvents(target), |
| msPointerMoveEvents(target), |
| msPointerMoveEvents(target), |
| msPointerMoveEvents(target), |
| msPointerUpEventsWithClick(target), |
| msPointerUpEventsWithClick(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 2, |
| goog.events.EventType.TOUCHMOVE, target, 2, |
| goog.events.EventType.TOUCHMOVE, target, 2, |
| goog.events.EventType.TOUCHEND, target, 2]); |
| } |
| } |
| |
| function verifyTapEvents(elem) { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(elem, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.release(); |
| assertFalse(touchscreen.isPressed()); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(elem), |
| msPointerUpEventsWithClick(elem)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, elem, 1, |
| goog.events.EventType.TOUCHEND, elem, 1, |
| goog.events.EventType.MOUSEMOVE, elem, |
| goog.events.EventType.MOUSEDOWN, elem, |
| goog.events.EventType.MOUSEUP, elem, |
| goog.events.EventType.CLICK, elem]); |
| } |
| } |
| |
| function testTouchScreenRelease() { |
| verifyTapEvents(target); |
| } |
| |
| function testTouchScreenReleaseOnNoTouchElement() { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| // Tap events should fire normally even if -ms-touch-action == auto. |
| verifyTapEvents(noTouchTarget); |
| } |
| |
| function testTouchScreenReleaseAfterMove() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| // After a move, the mouseclick should not happen. |
| touchscreen.move(target, new goog.math.Coordinate(10, 10)); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerMoveEvents(target), |
| msPointerUpEventsWithClick(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, |
| goog.events.EventType.TOUCHMOVE, target, 1, |
| goog.events.EventType.TOUCHEND, target, 1]); |
| } |
| } |
| |
| function testMsSetPointerCapture() { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| |
| touchscreen.move(captureTarget, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.move(lowerTarget, new goog.math.Coordinate(10, 10)); |
| touchscreen.release(); |
| |
| // The captureTarget calls msSetPointerCapture, so subsequent events |
| // should fire on captureTarget even after the move to lowerTarget. |
| assertEvents(msPointerDownEvents(captureTarget), |
| msPointerMoveEvents(captureTarget), |
| msPointerUpEventsWithoutClick(captureTarget)); |
| } |
| |
| function testBubblingMsSetPointerCapture() { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| |
| touchscreen.move(innerCaptureTarget, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.move(lowerTarget, new goog.math.Coordinate(10, 10)); |
| touchscreen.release(); |
| |
| // The MSPointerDown event on innerCaptureTarget bubbles up to the |
| // captureTarget element which calls msSetPointerCapture, so subsequent |
| // events should fire on captureTarget even after the move to lowerTarget. |
| assertEvents(msPointerDownEvents(innerCaptureTarget), |
| msPointerMoveEvents(captureTarget), |
| msPointerUpEventsWithoutClick(captureTarget)); |
| } |
| |
| function testClickDoesNotFireOnCapturedPointer() { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| |
| touchscreen.move(innerCaptureTarget, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.move(innerCaptureTarget, new goog.math.Coordinate(10, 10)); |
| touchscreen.release(); |
| |
| // After the pointer down event, captureTarget should receive the rest of |
| // the events except for the click event. |
| assertEvents(msPointerDownEvents(innerCaptureTarget), |
| msPointerMoveEvents(captureTarget), |
| [goog.events.EventType.MSPOINTERUP, captureTarget], |
| [goog.events.EventType.MOUSEUP, captureTarget], |
| [goog.events.EventType.CLICK, innerCaptureTarget], |
| [goog.events.EventType.MSPOINTEROUT, captureTarget], |
| [goog.events.EventType.MOUSEOUT, captureTarget]); |
| } |
| |
| function testTouchScreenReleaseAfterMoveOnNoTouchElement_IE() { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| touchscreen.move(noTouchTarget, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.move(noTouchTarget, new goog.math.Coordinate(10, 10)); |
| touchscreen.move(noTouchTarget, new goog.math.Coordinate(20, 20)); |
| touchscreen.release(); |
| |
| // Since the element does not support touch actions, the move triggers |
| // a pointerout and mouseout events followed by a pointer cancel. |
| assertEvents(msPointerDownEvents(noTouchTarget), |
| [goog.events.EventType.MSPOINTEROUT, noTouchTarget, |
| goog.events.EventType.MOUSEOUT, noTouchTarget, |
| goog.events.EventType.MSPOINTERCANCEL, noTouchTarget]); |
| } |
| |
| function testTouchScreenReleaseAfterNewElement() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| // After moving to a new element, the touchmove and touchend |
| // events should fire on the element where the touch started. |
| touchscreen.move(lowerTarget, new goog.math.Coordinate(0, 0)); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerMoveEvents(lowerTarget), |
| msPointerUpEventsWithoutClick(lowerTarget)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, |
| goog.events.EventType.TOUCHMOVE, target, 1, |
| goog.events.EventType.TOUCHEND, target, 1]); |
| } |
| } |
| |
| function testTouchScreenMoveWithoutPress() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| assertFalse(touchscreen.isPressed()); |
| } |
| |
| function testTouchScreenMoveWithPress() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.move(target, new goog.math.Coordinate(20, 20)); |
| assertTrue(touchscreen.isPressed()); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerMoveEvents(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, |
| goog.events.EventType.TOUCHMOVE, target, 1]); |
| } |
| } |
| |
| function testExceptionReleasingWhenNotPressed() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| assertThrows('Releasing when not pressed should throw an exception', |
| goog.bind(touchscreen.release, touchscreen)); |
| } |
| |
| function testExceptionPressedWhenAlreadyPressed() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| assertThrows('Pressing when already pressed should throw an exception', |
| goog.bind(touchscreen.press, touchscreen)); |
| } |
| |
| function testPreventDefaultOnTouchstart() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| goog.events.listen(target, goog.events.EventType.TOUCHSTART, function(e) { |
| e.preventDefault(); |
| }); |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerUpEventsWithClick(target)); |
| } else { |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, |
| goog.events.EventType.TOUCHEND, target, 1]); |
| } |
| } |
| |
| function testPreventDefaultOnTouchend() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { |
| return; |
| } |
| goog.events.listen(target, goog.events.EventType.TOUCHEND, function(e) { |
| e.preventDefault(); |
| }); |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.release(); |
| if (bot.userAgent.IE_DOC_10) { |
| assertEvents(msPointerDownEvents(target), |
| msPointerUpEventsWithClick(target)); |
| } else { |
| var events = [goog.events.EventType.TOUCHSTART, target, 1, |
| goog.events.EventType.TOUCHEND, target, 1]; |
| if (!bot.userAgent.IOS && !goog.userAgent.product.CHROME) { |
| events.push(goog.events.EventType.MOUSEMOVE, target, |
| goog.events.EventType.MOUSEDOWN, target, |
| goog.events.EventType.MOUSEUP, target, |
| goog.events.EventType.CLICK, target); |
| } |
| assertEvents(events); |
| } |
| } |
| |
| function testTouchEventCoords() { |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS || bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| window.scrollTo(20, 30); |
| // Yield to ensure all browsers apply the scrolling change. |
| // Relying on the implicit tick in a promise resolution is enough. |
| return goog.Promise.resolve().then(function() { |
| var coords = bot.dom.getClientRect(coordsTarget); |
| touchscreen.move(coordsTarget, new goog.math.Coordinate(0, 0)); |
| touchscreen.press(); |
| touchscreen.release(); |
| // The client coords of the touch event should be the top left of the |
| // target and the page coords should include the scroll offset. |
| assertEvents([coords.left, coords.top, |
| coords.left + 20, coords.top + 30]); |
| }); |
| } |
| </script> |
| </head> |
| <body> |
| TouchScreen Test.<br> |
| <div id="target" |
| style="background-color:blue; |
| width:200px; |
| height:100px; |
| -ms-touch-action:none"> |
| touch here |
| </div> |
| <div id="lower" |
| style="background-color:red; |
| width:50px; |
| height:50px; |
| position relative; |
| top:25px; |
| -ms-touch-action:none"> |
| lower |
| </div> |
| <div id="captureTarget" |
| style="background-color:green; |
| width:200px; |
| height:200px; |
| -ms-touch-action:none"> |
| ie 10 target |
| |
| <div id="innerCaptureTarget" |
| style="background-color:cyan; |
| width:100px; |
| height:50px; |
| -ms-touch-action:none"> |
| inner ie 10 target |
| </div> |
| </div> |
| <div id="notouch" |
| style="background-color:green; |
| width:100px; |
| height:100px; |
| position relative; |
| top:50px; |
| -ms-touch-action:auto"> |
| no touch |
| </div> |
| <div id="coordsTarget" |
| style="background-color:magenta; |
| width:8000px; |
| height:8000px; |
| -ms-touch-action:none"> |
| coords target |
| </div> |
| </body> |
| </html> |