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 |