OLD | NEW |
(Empty) | |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import logging |
| 6 |
| 7 from telemetry.page import page |
| 8 from telemetry.page import page_set |
| 9 |
| 10 |
| 11 _MOVE_GOOGLE_MAPS_JS = """ |
| 12 /** |
| 13 * Issues/dispatches keyboard event to target element. |
| 14 * @param {element} target Target element. |
| 15 * @param {string} eventType One of 'keyup', 'keydown', 'keypress'. |
| 16 * @param {number} keyCode Key code. |
| 17 */ |
| 18 function issueKeyEvent(target, eventType, keyCode) { |
| 19 var event = document.createEventObject ? |
| 20 document.createEventObject() : document.createEvent('Events'); |
| 21 |
| 22 if (event.initEvent) { |
| 23 event.initEvent(eventType, true, true); |
| 24 } |
| 25 |
| 26 event.keyCode = keyCode; |
| 27 event.which = keyCode; |
| 28 |
| 29 target.dispatchEvent ? |
| 30 target.dispatchEvent(event) : target.fireEvent('on' + eventType, event); |
| 31 } |
| 32 |
| 33 // Map keyboard shortcut to key code mapping. |
| 34 var MAP_KEYBOARD = { |
| 35 LEFT: 37, |
| 36 UP: 38, |
| 37 RIGHT: 39, |
| 38 DOWN: 40, |
| 39 ZOOM_IN: 187, |
| 40 ZOOM_OUT: 189 |
| 41 }; |
| 42 |
| 43 // The scene canvas is the first one on the page apparently. The 2nd one is the |
| 44 // minimap. I'd rely on the canvas ordering instead of the class since Tactile's |
| 45 // obfuscating classes soon. |
| 46 var sceneCanvas = document.querySelector('canvas'); |
| 47 |
| 48 /** |
| 49 * Moves Google maps. |
| 50 * @param {string} action Action defined in MAP_KEYBOARD. |
| 51 * @param {number} duration_msecs Duration (in ms) of the action. |
| 52 */ |
| 53 function moveMap(action, duration_msecs) { |
| 54 keycode = MAP_KEYBOARD[action]; |
| 55 issueKeyEvent(sceneCanvas, 'keydown', keycode); |
| 56 setTimeout(function() {issueKeyEvent(sceneCanvas, 'keyup', keycode);}, |
| 57 duration_msecs); |
| 58 } |
| 59 |
| 60 /** |
| 61 * Creates and dispatches mouse event. |
| 62 * @param {object} target DOM element to dispatch event to. |
| 63 * @param {string} eventType Mouse event, one of 'mousedown', 'mouseup', |
| 64 * 'mousemove' event. |
| 65 * @param {number} x clientX position. |
| 66 * @param {number} y clientY position. |
| 67 * @param {number} delay Milliseconds delay to dispatch the event. |
| 68 */ |
| 69 function dispatchMouseEvent(target, eventType, x, y, delay) { |
| 70 setTimeout(function() { |
| 71 /* TODO(deanliao): investigate why the new MouseEvent creator won't work. |
| 72 var button = eventType == 'mouseup' ? -1 : 0; |
| 73 var event = new MouseEvent( |
| 74 eventType, |
| 75 {clientX: x, |
| 76 clientY: y, |
| 77 button: button}); |
| 78 */ |
| 79 |
| 80 var event = document.createEvent('MouseEvents'); |
| 81 var detail = eventType == 'mousemove' ? 0 : 1; |
| 82 event.initMouseEvent(eventType, true, true, window, |
| 83 detail, x, y, x, y); |
| 84 |
| 85 target.dispatchEvent(event); |
| 86 |
| 87 }, delay); |
| 88 } |
| 89 |
| 90 |
| 91 /** |
| 92 * Drag-n-drops mouse linearly for a while. |
| 93 * @param {object} target DOM element to dispatch event to. |
| 94 * @param {number} startX Starting clientX position. |
| 95 * @param {number} startY Starting clientY position. |
| 96 * @param {number} endX Starting clientX position. |
| 97 * @param {number} endY Starting clientY position. |
| 98 * @param {number} duration Drag for milliseconds. |
| 99 */ |
| 100 function linearMouseDragDrop(target, startX, startY, endX, endY, duration) { |
| 101 var interval = 10; |
| 102 var numSteps = Math.floor(duration / interval) - 1; |
| 103 var deltaX = (endX - startX) / numSteps; |
| 104 var deltaY = (endY - startY) / numSteps; |
| 105 var x = startX; |
| 106 var y = startY; |
| 107 var delay = 0; |
| 108 dispatchMouseEvent(target, 'mousedown', x, y, delay); |
| 109 for (i = 1; i < numSteps; i++) { |
| 110 x = Math.floor(startX + i * deltaX); |
| 111 y = Math.floor(startY + i * deltaY); |
| 112 delay += interval; |
| 113 dispatchMouseEvent(target, 'mousemove', x, y, delay); |
| 114 } |
| 115 dispatchMouseEvent(target, 'mouseup', endX, endY, delay + interval); |
| 116 } |
| 117 """ |
| 118 |
| 119 |
| 120 class MapsEarthPage(page.Page): |
| 121 """Page for surfing Google Maps with Earth layer.""" |
| 122 |
| 123 _MAP_MODE_SWITCHER = '.widget-minimap-shim-button' |
| 124 _START_END_COORD = { |
| 125 'LEFT': (700, 380, 20, 380), |
| 126 'RIGHT': (20, 380, 700, 380), |
| 127 'UP': (500, 600, 500, 20), |
| 128 'DOWN': (500, 20, 500, 600)} |
| 129 |
| 130 def __init__(self, parent_page_set, url, page_name, map_load_wait_secs=10, |
| 131 drag_duration_ms=500): |
| 132 super(MapsEarthPage, self).__init__( |
| 133 url=url, |
| 134 page_set=parent_page_set, |
| 135 name=page_name) |
| 136 self._map_load_wait_sec = map_load_wait_secs |
| 137 self._drag_duration_ms = drag_duration_ms |
| 138 |
| 139 def CanRunOnBrowser(self, browser_info): |
| 140 if not browser_info.HasWebGLSupport(): |
| 141 logging.warning('Browser does not support webgl, skipping test') |
| 142 return False |
| 143 return True |
| 144 |
| 145 def RunNavigateSteps(self, action_runner): |
| 146 super(MapsEarthPage, self).RunNavigateSteps(action_runner) |
| 147 logging.info('Wait for Google Maps mode switcher') |
| 148 action_runner.WaitForElement(selector=self._MAP_MODE_SWITCHER) |
| 149 logging.info('Loaded. Wait for %d more seconds...' % |
| 150 self._map_load_wait_sec) |
| 151 action_runner.Wait(self._map_load_wait_sec) |
| 152 self.PrepareInteraction(action_runner) |
| 153 |
| 154 def MouseDrag(self, action_runner, direction, duration_ms): |
| 155 """Drags mouse on the map. |
| 156 |
| 157 Args: |
| 158 action_runner: Telemetry action runner. |
| 159 direction: Drag direction. One of 'UP', 'DOWN', 'LEFT', 'RIGHT'. |
| 160 duration_ms: Duration of the drag. |
| 161 """ |
| 162 if direction not in self._START_END_COORD: |
| 163 logging.error('Invalid direction %r. Should be one of %r', direction, |
| 164 self._START_END_COORD.keys()) |
| 165 return |
| 166 start_end_coord = ', '.join( |
| 167 str(x) for x in self._START_END_COORD[direction]) |
| 168 js = 'linearMouseDragDrop(sceneCanvas, %s, %d);' % (start_end_coord, |
| 169 duration_ms) |
| 170 logging.info('MouseDrag %s for %d ms. Execute %s', direction, duration_ms, |
| 171 js) |
| 172 action_runner.ExecuteJavaScript(js) |
| 173 action_runner.Wait(duration_ms / 1000.0 + 0.2) |
| 174 |
| 175 def RunPageInteractions(self, action_runner): |
| 176 logging.info('RunPageInteractions') |
| 177 for action in ['DOWN', 'LEFT', 'LEFT', 'UP', 'RIGHT', 'RIGHT', 'UP', |
| 178 'LEFT', 'LEFT', 'UP', 'RIGHT', 'RIGHT', 'UP', 'LEFT', |
| 179 'LEFT']: |
| 180 self.MouseDrag(action_runner, action, self._drag_duration_ms) |
| 181 |
| 182 # TODO(deanliao): figure out why keyboard event doesn't work. |
| 183 # for action in |
| 184 # logging.info('moveMap ' + action) |
| 185 # action_runner.ExecuteJavaScript( |
| 186 # "moveMap('%s', %d);" % (action, self._KEYDOWN_MSEC)) |
| 187 # action_runner.Wait(self._ACTION_INTERVAL_SECS) |
| 188 |
| 189 def PrepareInteraction(self, action_runner): |
| 190 action_runner.ExecuteJavaScript(_MOVE_GOOGLE_MAPS_JS) |
| 191 logging.info('_MOVE_GOOGLE_MAPS_JS injected.') |
| 192 |
| 193 |
| 194 class MapsEarthPageSet(page_set.PageSet): |
| 195 """Page set for Google Maps with Earth layer.""" |
| 196 |
| 197 def __init__(self): |
| 198 super(MapsEarthPageSet, self).__init__( |
| 199 archive_data_file='data/maps_earth.json', |
| 200 bucket=page_set.PUBLIC_BUCKET) |
| 201 |
| 202 self.AddUserStory( |
| 203 MapsEarthPage( |
| 204 self, |
| 205 'https://www.google.com/maps/@37.7502889,-122.4791582,15z', |
| 206 'Maps.SanFrancisco', |
| 207 map_load_wait_secs=3, |
| 208 drag_duration_ms=1500)) |
| 209 |
| 210 # Temporary disable Earth test as it doesn't run smooth yet. |
| 211 # self.AddUserStory( |
| 212 # MapsEarthPage( |
| 213 # self, |
| 214 # 'https://goo.gl/maps/NRtaW', |
| 215 # 'Maps.SanFranciscoEarth', |
| 216 # map_load_wait_secs=10, |
| 217 # drag_duration_ms=2000)) |
OLD | NEW |