71b225a8b60b2bd336165cc2d2132ec836cc90e7
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / test / run_py_tests.py
1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """End to end tests for ChromeDriver."""
7
8 import base64
9 import json
10 import math
11 import optparse
12 import os
13 import socket
14 import subprocess
15 import sys
16 import tempfile
17 import threading
18 import time
19 import unittest
20 import urllib2
21
22 _THIS_DIR = os.path.abspath(os.path.dirname(__file__))
23 sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir))
24 sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir, 'client'))
25 sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir, 'server'))
26
27 import chrome_paths
28 import chromedriver
29 import unittest_util
30 import util
31 import server
32 from webelement import WebElement
33 import webserver
34
35 _TEST_DATA_DIR = os.path.join(chrome_paths.GetTestData(), 'chromedriver')
36
37 if util.IsLinux():
38   sys.path.insert(0, os.path.join(chrome_paths.GetSrc(), 'build', 'android'))
39   from pylib import android_commands
40   from pylib import constants
41   from pylib import forwarder
42   from pylib import valgrind_tools
43   from pylib.device import device_utils
44
45
46 _NEGATIVE_FILTER = [
47     # https://code.google.com/p/chromedriver/issues/detail?id=213
48     'ChromeDriverTest.testClickElementInSubFrame',
49     # This test is flaky since it uses setTimeout.
50     # Re-enable once crbug.com/177511 is fixed and we can remove setTimeout.
51     'ChromeDriverTest.testAlert',
52 ]
53
54 _VERSION_SPECIFIC_FILTER = {}
55 _VERSION_SPECIFIC_FILTER['HEAD'] = [
56     # https://code.google.com/p/chromedriver/issues/detail?id=815
57     'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
58 ]
59
60 _OS_SPECIFIC_FILTER = {}
61 _OS_SPECIFIC_FILTER['win'] = [
62     # https://code.google.com/p/chromedriver/issues/detail?id=214
63     'ChromeDriverTest.testCloseWindow',
64     # https://code.google.com/p/chromedriver/issues/detail?id=299
65     'ChromeLogPathCapabilityTest.testChromeLogPath',
66 ]
67 _OS_SPECIFIC_FILTER['linux'] = [
68     # Xvfb doesn't support maximization.
69     'ChromeDriverTest.testWindowMaximize',
70     # https://code.google.com/p/chromedriver/issues/detail?id=302
71     'ChromeDriverTest.testWindowPosition',
72     'ChromeDriverTest.testWindowSize',
73 ]
74 _OS_SPECIFIC_FILTER['mac'] = [
75     # https://code.google.com/p/chromedriver/issues/detail?id=304
76     'ChromeDriverTest.testGoBackAndGoForward',
77 ]
78
79 _DESKTOP_NEGATIVE_FILTER = [
80     # Desktop doesn't support touch (without --touch-events).
81     'ChromeDriverTest.testSingleTapElement',
82     'ChromeDriverTest.testTouchDownUpElement',
83     'ChromeDriverTest.testTouchFlickElement',
84     'ChromeDriverTest.testTouchMovedElement',
85     'ChromeDriverAndroidTest.*',
86 ]
87
88
89 def _GetDesktopNegativeFilter(version_name):
90   filter = _NEGATIVE_FILTER + _DESKTOP_NEGATIVE_FILTER
91   os = util.GetPlatformName()
92   if os in _OS_SPECIFIC_FILTER:
93     filter += _OS_SPECIFIC_FILTER[os]
94   if version_name in _VERSION_SPECIFIC_FILTER:
95     filter += _VERSION_SPECIFIC_FILTER[version_name]
96   return filter
97
98 _ANDROID_NEGATIVE_FILTER = {}
99 _ANDROID_NEGATIVE_FILTER['chrome'] = (
100     _NEGATIVE_FILTER + [
101         # TODO(chrisgao): fix hang of tab crash test on android.
102         'ChromeDriverTest.testTabCrash',
103         # Android doesn't support switches and extensions.
104         'ChromeSwitchesCapabilityTest.*',
105         'ChromeExtensionsCapabilityTest.*',
106         'MobileEmulationCapabilityTest.*',
107         # https://crbug.com/274650
108         'ChromeDriverTest.testCloseWindow',
109         # https://code.google.com/p/chromedriver/issues/detail?id=270
110         'ChromeDriverTest.testPopups',
111         # https://code.google.com/p/chromedriver/issues/detail?id=298
112         'ChromeDriverTest.testWindowPosition',
113         'ChromeDriverTest.testWindowSize',
114         'ChromeDriverTest.testWindowMaximize',
115         'ChromeLogPathCapabilityTest.testChromeLogPath',
116         'RemoteBrowserTest.*',
117         # Don't enable perf testing on Android yet.
118         'PerfTest.testSessionStartTime',
119         'PerfTest.testSessionStopTime',
120         'PerfTest.testColdExecuteScript',
121         # https://code.google.com/p/chromedriver/issues/detail?id=459
122         'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
123     ]
124 )
125 _ANDROID_NEGATIVE_FILTER['chrome_stable'] = (
126     _ANDROID_NEGATIVE_FILTER['chrome'])
127 _ANDROID_NEGATIVE_FILTER['chrome_beta'] = (
128     _ANDROID_NEGATIVE_FILTER['chrome'])
129 _ANDROID_NEGATIVE_FILTER['chrome_shell'] = (
130     _ANDROID_NEGATIVE_FILTER['chrome'] + [
131         # ChromeShell doesn't support multiple tabs.
132         'ChromeDriverTest.testGetWindowHandles',
133         'ChromeDriverTest.testSwitchToWindow',
134         'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
135     ]
136 )
137 _ANDROID_NEGATIVE_FILTER['chromedriver_webview_shell'] = (
138     _ANDROID_NEGATIVE_FILTER['chrome_shell'])
139
140
141 class ChromeDriverBaseTest(unittest.TestCase):
142   """Base class for testing chromedriver functionalities."""
143
144   def __init__(self, *args, **kwargs):
145     super(ChromeDriverBaseTest, self).__init__(*args, **kwargs)
146     self._drivers = []
147
148   def tearDown(self):
149     for driver in self._drivers:
150       try:
151         driver.Quit()
152       except:
153         pass
154
155   def CreateDriver(self, server_url=None, **kwargs):
156     if server_url is None:
157       server_url = _CHROMEDRIVER_SERVER_URL
158
159     android_package = None
160     android_activity = None
161     android_process = None
162     if _ANDROID_PACKAGE_KEY:
163       android_package = constants.PACKAGE_INFO[_ANDROID_PACKAGE_KEY].package
164       if _ANDROID_PACKAGE_KEY == 'chromedriver_webview_shell':
165         android_activity = constants.PACKAGE_INFO[_ANDROID_PACKAGE_KEY].activity
166         android_process = '%s:main' % android_package
167
168     driver = chromedriver.ChromeDriver(server_url,
169                                        chrome_binary=_CHROME_BINARY,
170                                        android_package=android_package,
171                                        android_activity=android_activity,
172                                        android_process=android_process,
173                                        **kwargs)
174     self._drivers += [driver]
175     return driver
176
177
178 class ChromeDriverTest(ChromeDriverBaseTest):
179   """End to end tests for ChromeDriver."""
180
181   @staticmethod
182   def GlobalSetUp():
183     ChromeDriverTest._http_server = webserver.WebServer(
184         chrome_paths.GetTestData())
185     ChromeDriverTest._sync_server = webserver.SyncWebServer()
186     if _ANDROID_PACKAGE_KEY:
187       ChromeDriverTest._device = device_utils.DeviceUtils(
188           android_commands.GetAttachedDevices()[0])
189       http_host_port = ChromeDriverTest._http_server._server.server_port
190       sync_host_port = ChromeDriverTest._sync_server._server.server_port
191       forwarder.Forwarder.Map(
192           [(http_host_port, http_host_port), (sync_host_port, sync_host_port)],
193           ChromeDriverTest._device)
194
195   @staticmethod
196   def GlobalTearDown():
197     if _ANDROID_PACKAGE_KEY:
198       forwarder.Forwarder.UnmapAllDevicePorts(ChromeDriverTest._device)
199     ChromeDriverTest._http_server.Shutdown()
200
201   @staticmethod
202   def GetHttpUrlForFile(file_path):
203     return ChromeDriverTest._http_server.GetUrl() + file_path
204
205   def setUp(self):
206     self._driver = self.CreateDriver()
207
208   def testStartStop(self):
209     pass
210
211   def testLoadUrl(self):
212     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
213
214   def testGetCurrentWindowHandle(self):
215     self._driver.GetCurrentWindowHandle()
216
217   def _WaitForNewWindow(self, old_handles):
218     """Wait for at least one new window to show up in 20 seconds.
219
220     Args:
221       old_handles: Handles to all old windows before the new window is added.
222
223     Returns:
224       Handle to a new window. None if timeout.
225     """
226     timeout = time.time() + 20
227     while time.time() < timeout:
228       new_handles = self._driver.GetWindowHandles()
229       if len(new_handles) > len(old_handles):
230         for index, old_handle in enumerate(old_handles):
231           self.assertEquals(old_handle, new_handles[index])
232         return new_handles[len(old_handles)]
233       time.sleep(0.01)
234     return None
235
236   def testCloseWindow(self):
237     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
238     old_handles = self._driver.GetWindowHandles()
239     self._driver.FindElement('id', 'link').Click()
240     new_window_handle = self._WaitForNewWindow(old_handles)
241     self.assertNotEqual(None, new_window_handle)
242     self._driver.SwitchToWindow(new_window_handle)
243     self.assertEquals(new_window_handle, self._driver.GetCurrentWindowHandle())
244     self.assertRaises(chromedriver.NoSuchElement,
245                       self._driver.FindElement, 'id', 'link')
246     self._driver.CloseWindow()
247     self.assertRaises(chromedriver.NoSuchWindow,
248                       self._driver.GetCurrentWindowHandle)
249     new_handles = self._driver.GetWindowHandles()
250     for old_handle in old_handles:
251       self.assertTrue(old_handle in new_handles)
252     for handle in new_handles:
253       self._driver.SwitchToWindow(handle)
254       self.assertEquals(handle, self._driver.GetCurrentWindowHandle())
255       self._driver.CloseWindow()
256
257   def testGetWindowHandles(self):
258     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
259     old_handles = self._driver.GetWindowHandles()
260     self._driver.FindElement('id', 'link').Click()
261     self.assertNotEqual(None, self._WaitForNewWindow(old_handles))
262
263   def testSwitchToWindow(self):
264     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
265     self.assertEquals(
266         1, self._driver.ExecuteScript('window.name = "oldWindow"; return 1;'))
267     window1_handle = self._driver.GetCurrentWindowHandle()
268     old_handles = self._driver.GetWindowHandles()
269     self._driver.FindElement('id', 'link').Click()
270     new_window_handle = self._WaitForNewWindow(old_handles)
271     self.assertNotEqual(None, new_window_handle)
272     self._driver.SwitchToWindow(new_window_handle)
273     self.assertEquals(new_window_handle, self._driver.GetCurrentWindowHandle())
274     self.assertRaises(chromedriver.NoSuchElement,
275                       self._driver.FindElement, 'id', 'link')
276     self._driver.SwitchToWindow('oldWindow')
277     self.assertEquals(window1_handle, self._driver.GetCurrentWindowHandle())
278
279   def testEvaluateScript(self):
280     self.assertEquals(1, self._driver.ExecuteScript('return 1'))
281     self.assertEquals(None, self._driver.ExecuteScript(''))
282
283   def testEvaluateScriptWithArgs(self):
284     script = ('document.body.innerHTML = "<div>b</div><div>c</div>";'
285               'return {stuff: document.querySelectorAll("div")};')
286     stuff = self._driver.ExecuteScript(script)['stuff']
287     script = 'return arguments[0].innerHTML + arguments[1].innerHTML'
288     self.assertEquals(
289         'bc', self._driver.ExecuteScript(script, stuff[0], stuff[1]))
290
291   def testEvaluateInvalidScript(self):
292     self.assertRaises(chromedriver.ChromeDriverException,
293                       self._driver.ExecuteScript, '{{{')
294
295   def testExecuteAsyncScript(self):
296     self._driver.SetTimeout('script', 3000)
297     self.assertRaises(
298         chromedriver.ScriptTimeout,
299         self._driver.ExecuteAsyncScript,
300         'var callback = arguments[0];'
301         'setTimeout(function(){callback(1);}, 10000);')
302     self.assertEquals(
303         2,
304         self._driver.ExecuteAsyncScript(
305             'var callback = arguments[0];'
306             'setTimeout(function(){callback(2);}, 300);'))
307
308   def testSwitchToFrame(self):
309     self._driver.ExecuteScript(
310         'var frame = document.createElement("iframe");'
311         'frame.id="id";'
312         'frame.name="name";'
313         'document.body.appendChild(frame);')
314     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
315     self._driver.SwitchToFrame('id')
316     self.assertTrue(self._driver.ExecuteScript('return window.top != window'))
317     self._driver.SwitchToMainFrame()
318     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
319     self._driver.SwitchToFrame('name')
320     self.assertTrue(self._driver.ExecuteScript('return window.top != window'))
321     self._driver.SwitchToMainFrame()
322     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
323     self._driver.SwitchToFrameByIndex(0)
324     self.assertTrue(self._driver.ExecuteScript('return window.top != window'))
325     self._driver.SwitchToMainFrame()
326     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
327     self._driver.SwitchToFrame(self._driver.FindElement('tag name', 'iframe'))
328     self.assertTrue(self._driver.ExecuteScript('return window.top != window'))
329
330   def testSwitchToParentFrame(self):
331     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/nested.html'))
332     self.assertTrue('One' in self._driver.GetPageSource())
333     self._driver.SwitchToFrameByIndex(0)
334     self.assertTrue('Two' in self._driver.GetPageSource())
335     self._driver.SwitchToFrameByIndex(0)
336     self.assertTrue('Three' in self._driver.GetPageSource())
337     self._driver.SwitchToParentFrame()
338     self.assertTrue('Two' in self._driver.GetPageSource())
339     self._driver.SwitchToParentFrame()
340     self.assertTrue('One' in self._driver.GetPageSource())
341
342   def testExecuteInRemovedFrame(self):
343     self._driver.ExecuteScript(
344         'var frame = document.createElement("iframe");'
345         'frame.id="id";'
346         'frame.name="name";'
347         'document.body.appendChild(frame);'
348         'window.addEventListener("message",'
349         '    function(event) { document.body.removeChild(frame); });')
350     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
351     self._driver.SwitchToFrame('id')
352     self.assertTrue(self._driver.ExecuteScript('return window.top != window'))
353     self._driver.ExecuteScript('parent.postMessage("remove", "*");')
354     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
355
356   def testGetTitle(self):
357     script = 'document.title = "title"; return 1;'
358     self.assertEquals(1, self._driver.ExecuteScript(script))
359     self.assertEquals('title', self._driver.GetTitle())
360
361   def testGetPageSource(self):
362     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
363     self.assertTrue('Link to empty.html' in self._driver.GetPageSource())
364
365   def testFindElement(self):
366     self._driver.ExecuteScript(
367         'document.body.innerHTML = "<div>a</div><div>b</div>";')
368     self.assertTrue(
369         isinstance(self._driver.FindElement('tag name', 'div'), WebElement))
370
371   def testFindElements(self):
372     self._driver.ExecuteScript(
373         'document.body.innerHTML = "<div>a</div><div>b</div>";')
374     divs = self._driver.FindElements('tag name', 'div')
375     self.assertTrue(isinstance(divs, list))
376     self.assertEquals(2, len(divs))
377     for div in divs:
378       self.assertTrue(isinstance(div, WebElement))
379
380   def testFindChildElement(self):
381     self._driver.ExecuteScript(
382         'document.body.innerHTML = "<div><br><br></div><div><a></a></div>";')
383     element = self._driver.FindElement('tag name', 'div')
384     self.assertTrue(
385         isinstance(element.FindElement('tag name', 'br'), WebElement))
386
387   def testFindChildElements(self):
388     self._driver.ExecuteScript(
389         'document.body.innerHTML = "<div><br><br></div><div><br></div>";')
390     element = self._driver.FindElement('tag name', 'div')
391     brs = element.FindElements('tag name', 'br')
392     self.assertTrue(isinstance(brs, list))
393     self.assertEquals(2, len(brs))
394     for br in brs:
395       self.assertTrue(isinstance(br, WebElement))
396
397   def testHoverOverElement(self):
398     div = self._driver.ExecuteScript(
399         'document.body.innerHTML = "<div>old</div>";'
400         'var div = document.getElementsByTagName("div")[0];'
401         'div.addEventListener("mouseover", function() {'
402         '  document.body.appendChild(document.createElement("br"));'
403         '});'
404         'return div;')
405     div.HoverOver()
406     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
407
408   def testClickElement(self):
409     div = self._driver.ExecuteScript(
410         'document.body.innerHTML = "<div>old</div>";'
411         'var div = document.getElementsByTagName("div")[0];'
412         'div.addEventListener("click", function() {'
413         '  div.innerHTML="new<br>";'
414         '});'
415         'return div;')
416     div.Click()
417     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
418
419   def testSingleTapElement(self):
420     div = self._driver.ExecuteScript(
421         'document.body.innerHTML = "<div>old</div>";'
422         'var div = document.getElementsByTagName("div")[0];'
423         'div.addEventListener("touchend", function() {'
424         '  div.innerHTML="new<br>";'
425         '});'
426         'return div;')
427     div.SingleTap()
428     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
429
430   def testTouchDownUpElement(self):
431     div = self._driver.ExecuteScript(
432         'document.body.innerHTML = "<div>old</div>";'
433         'var div = document.getElementsByTagName("div")[0];'
434         'div.addEventListener("touchend", function() {'
435         '  div.innerHTML="new<br>";'
436         '});'
437         'return div;')
438     loc = div.GetLocation()
439     self._driver.TouchDown(loc['x'], loc['y'])
440     self._driver.TouchUp(loc['x'], loc['y'])
441     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
442
443   def testTouchFlickElement(self):
444     dx = 3
445     dy = 4
446     speed = 5
447     flickTouchEventsPerSecond = 30
448     moveEvents = int(
449         math.sqrt(dx * dx + dy * dy) * flickTouchEventsPerSecond / speed)
450     div = self._driver.ExecuteScript(
451         'document.body.innerHTML = "<div>old</div>";'
452         'var div = document.getElementsByTagName("div")[0];'
453         'div.addEventListener("touchstart", function() {'
454         '  div.innerHTML = "preMove0";'
455         '});'
456         'div.addEventListener("touchmove", function() {'
457         '  res = div.innerHTML.match(/preMove(\d+)/);'
458         '  if (res != null) {'
459         '    div.innerHTML = "preMove" + (parseInt(res[1], 10) + 1);'
460         '  }'
461         '});'
462         'div.addEventListener("touchend", function() {'
463         '  if (div.innerHTML == "preMove' + str(moveEvents) + '") {'
464         '    div.innerHTML = "new<br>";'
465         '  }'
466         '});'
467         'return div;')
468     self._driver.TouchFlick(div, dx, dy, speed)
469     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
470
471   def testTouchMovedElement(self):
472     div = self._driver.ExecuteScript(
473         'document.body.innerHTML = "<div>old</div>";'
474         'var div = document.getElementsByTagName("div")[0];'
475         'div.addEventListener("touchmove", function() {'
476         '  div.innerHTML="new<br>";'
477         '});'
478         'return div;')
479     loc = div.GetLocation()
480     self._driver.TouchDown(loc['x'], loc['y'])
481     self._driver.TouchMove(loc['x'] + 1, loc['y'] + 1)
482     self._driver.TouchUp(loc['x'] + 1, loc['y'] + 1)
483     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
484
485   def testClickElementInSubFrame(self):
486     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/frame_test.html'))
487     frame = self._driver.FindElement('tag name', 'iframe')
488     self._driver.SwitchToFrame(frame)
489     # Test clicking element in the sub frame.
490     self.testClickElement()
491
492   def testClearElement(self):
493     text = self._driver.ExecuteScript(
494         'document.body.innerHTML = \'<input type="text" value="abc">\';'
495         'var input = document.getElementsByTagName("input")[0];'
496         'input.addEventListener("change", function() {'
497         '  document.body.appendChild(document.createElement("br"));'
498         '});'
499         'return input;')
500     text.Clear()
501     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
502
503   def testSendKeysToElement(self):
504     text = self._driver.ExecuteScript(
505         'document.body.innerHTML = \'<input type="text">\';'
506         'var input = document.getElementsByTagName("input")[0];'
507         'input.addEventListener("change", function() {'
508         '  document.body.appendChild(document.createElement("br"));'
509         '});'
510         'return input;')
511     text.SendKeys('0123456789+-*/ Hi')
512     text.SendKeys(', there!')
513     value = self._driver.ExecuteScript('return arguments[0].value;', text)
514     self.assertEquals('0123456789+-*/ Hi, there!', value)
515
516   def testGetCurrentUrl(self):
517     self.assertEquals('data:,', self._driver.GetCurrentUrl())
518
519   def testGoBackAndGoForward(self):
520     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
521     self._driver.GoBack()
522     self._driver.GoForward()
523
524   def testRefresh(self):
525     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
526     self._driver.Refresh()
527
528   def testMouseMoveTo(self):
529     div = self._driver.ExecuteScript(
530         'document.body.innerHTML = "<div>old</div>";'
531         'var div = document.getElementsByTagName("div")[0];'
532         'div.style["width"] = "100px";'
533         'div.style["height"] = "100px";'
534         'div.addEventListener("mouseover", function() {'
535         '  var div = document.getElementsByTagName("div")[0];'
536         '  div.innerHTML="new<br>";'
537         '});'
538         'return div;')
539     self._driver.MouseMoveTo(div, 10, 10)
540     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
541
542   def testMouseClick(self):
543     div = self._driver.ExecuteScript(
544         'document.body.innerHTML = "<div>old</div>";'
545         'var div = document.getElementsByTagName("div")[0];'
546         'div.style["width"] = "100px";'
547         'div.style["height"] = "100px";'
548         'div.addEventListener("click", function() {'
549         '  var div = document.getElementsByTagName("div")[0];'
550         '  div.innerHTML="new<br>";'
551         '});'
552         'return div;')
553     self._driver.MouseMoveTo(div)
554     self._driver.MouseClick()
555     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
556
557   def testMouseButtonDownAndUp(self):
558     self._driver.ExecuteScript(
559         'document.body.innerHTML = "<div>old</div>";'
560         'var div = document.getElementsByTagName("div")[0];'
561         'div.style["width"] = "100px";'
562         'div.style["height"] = "100px";'
563         'div.addEventListener("mousedown", function() {'
564         '  var div = document.getElementsByTagName("div")[0];'
565         '  div.innerHTML="new1<br>";'
566         '});'
567         'div.addEventListener("mouseup", function() {'
568         '  var div = document.getElementsByTagName("div")[0];'
569         '  div.innerHTML="new2<a></a>";'
570         '});')
571     self._driver.MouseMoveTo(None, 50, 50)
572     self._driver.MouseButtonDown()
573     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
574     self._driver.MouseButtonUp()
575     self.assertEquals(1, len(self._driver.FindElements('tag name', 'a')))
576
577   def testMouseDoubleClick(self):
578     div = self._driver.ExecuteScript(
579         'document.body.innerHTML = "<div>old</div>";'
580         'var div = document.getElementsByTagName("div")[0];'
581         'div.style["width"] = "100px";'
582         'div.style["height"] = "100px";'
583         'div.addEventListener("dblclick", function() {'
584         '  var div = document.getElementsByTagName("div")[0];'
585         '  div.innerHTML="new<br>";'
586         '});'
587         'return div;')
588     self._driver.MouseMoveTo(div, 1, 1)
589     self._driver.MouseDoubleClick()
590     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
591
592   def testAlert(self):
593     self.assertFalse(self._driver.IsAlertOpen())
594     self._driver.ExecuteScript(
595         'window.setTimeout('
596         '    function() { window.confirmed = confirm(\'HI\'); },'
597         '    0);')
598     self.assertTrue(self._driver.IsAlertOpen())
599     self.assertEquals('HI', self._driver.GetAlertMessage())
600     self._driver.HandleAlert(False)
601     self.assertFalse(self._driver.IsAlertOpen())
602     self.assertEquals(False,
603                       self._driver.ExecuteScript('return window.confirmed'))
604
605   def testShouldHandleNewWindowLoadingProperly(self):
606     """Tests that ChromeDriver determines loading correctly for new windows."""
607     self._http_server.SetDataForPath(
608         '/newwindow',
609         """
610         <html>
611         <body>
612         <a href='%s' target='_blank'>new window/tab</a>
613         </body>
614         </html>""" % self._sync_server.GetUrl())
615     self._driver.Load(self._http_server.GetUrl() + '/newwindow')
616     old_windows = self._driver.GetWindowHandles()
617     self._driver.FindElement('tagName', 'a').Click()
618     new_window = self._WaitForNewWindow(old_windows)
619     self.assertNotEqual(None, new_window)
620
621     self.assertFalse(self._driver.IsLoading())
622     self._driver.SwitchToWindow(new_window)
623     self.assertTrue(self._driver.IsLoading())
624     self._sync_server.RespondWithContent('<html>new window</html>')
625     self._driver.ExecuteScript('return 1')  # Shouldn't hang.
626
627   def testPopups(self):
628     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
629     old_handles = self._driver.GetWindowHandles()
630     self._driver.ExecuteScript('window.open("about:blank")')
631     new_window_handle = self._WaitForNewWindow(old_handles)
632     self.assertNotEqual(None, new_window_handle)
633
634   def testNoSuchFrame(self):
635     self.assertRaises(chromedriver.NoSuchFrame,
636                       self._driver.SwitchToFrame, 'nosuchframe')
637     self.assertRaises(chromedriver.NoSuchFrame,
638                       self._driver.SwitchToFrame,
639                       self._driver.FindElement('tagName', 'body'))
640
641   def testWindowPosition(self):
642     position = self._driver.GetWindowPosition()
643     self._driver.SetWindowPosition(position[0], position[1])
644     self.assertEquals(position, self._driver.GetWindowPosition())
645
646     # Resize so the window isn't moved offscreen.
647     # See https://code.google.com/p/chromedriver/issues/detail?id=297.
648     self._driver.SetWindowSize(300, 300)
649
650     self._driver.SetWindowPosition(100, 200)
651     self.assertEquals([100, 200], self._driver.GetWindowPosition())
652
653   def testWindowSize(self):
654     size = self._driver.GetWindowSize()
655     self._driver.SetWindowSize(size[0], size[1])
656     self.assertEquals(size, self._driver.GetWindowSize())
657
658     self._driver.SetWindowSize(600, 400)
659     self.assertEquals([600, 400], self._driver.GetWindowSize())
660
661   def testWindowMaximize(self):
662     self._driver.SetWindowPosition(100, 200)
663     self._driver.SetWindowSize(600, 400)
664     self._driver.MaximizeWindow()
665
666     self.assertNotEqual([100, 200], self._driver.GetWindowPosition())
667     self.assertNotEqual([600, 400], self._driver.GetWindowSize())
668     # Set size first so that the window isn't moved offscreen.
669     # See https://code.google.com/p/chromedriver/issues/detail?id=297.
670     self._driver.SetWindowSize(600, 400)
671     self._driver.SetWindowPosition(100, 200)
672     self.assertEquals([100, 200], self._driver.GetWindowPosition())
673     self.assertEquals([600, 400], self._driver.GetWindowSize())
674
675   def testConsoleLogSources(self):
676     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/console_log.html'))
677     logs = self._driver.GetLog('browser')
678     self.assertEquals(len(logs), 2)
679     self.assertEquals(logs[0]['source'], 'network')
680     self.assertEquals(logs[1]['source'], 'javascript')
681
682   def testAutoReporting(self):
683     self.assertFalse(self._driver.IsAutoReporting())
684     self._driver.SetAutoReporting(True)
685     self.assertTrue(self._driver.IsAutoReporting())
686     url = self.GetHttpUrlForFile('/chromedriver/console_log.html')
687     self.assertRaisesRegexp(chromedriver.UnknownError,
688                             '.*(404|Failed to load resource).*',
689                             self._driver.Load,
690                             url)
691
692   def testContextMenuEventFired(self):
693     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/context_menu.html'))
694     self._driver.MouseMoveTo(self._driver.FindElement('tagName', 'div'))
695     self._driver.MouseClick(2)
696     self.assertTrue(self._driver.ExecuteScript('return success'))
697
698   def testHasFocusOnStartup(self):
699     # Some pages (about:blank) cause Chrome to put the focus in URL bar.
700     # This breaks tests depending on focus.
701     self.assertTrue(self._driver.ExecuteScript('return document.hasFocus()'))
702
703   def testTabCrash(self):
704     # If a tab is crashed, the session will be deleted.
705     # When 31 is released, will reload the tab instead.
706     # https://code.google.com/p/chromedriver/issues/detail?id=547
707     self.assertRaises(chromedriver.UnknownError,
708                       self._driver.Load, 'chrome://crash')
709     self.assertRaises(chromedriver.NoSuchSession,
710                       self._driver.GetCurrentUrl)
711
712   def testDoesntHangOnDebugger(self):
713     self._driver.ExecuteScript('debugger;')
714
715   def testMobileEmulationDisabledByDefault(self):
716     self.assertFalse(self._driver.capabilities['mobileEmulationEnabled'])
717
718
719 class ChromeDriverAndroidTest(ChromeDriverBaseTest):
720   """End to end tests for Android-specific tests."""
721
722   def testLatestAndroidAppInstalled(self):
723     if ('stable' not in _ANDROID_PACKAGE_KEY and
724         'beta' not in _ANDROID_PACKAGE_KEY):
725       return
726
727     self._driver = self.CreateDriver()
728
729     try:
730       omaha_list = json.loads(
731           urllib2.urlopen('http://omahaproxy.appspot.com/all.json').read())
732       for l in omaha_list:
733         if l['os'] != 'android':
734           continue
735         for v in l['versions']:
736           if (('stable' in v['channel'] and 'stable' in _ANDROID_PACKAGE_KEY) or
737               ('beta' in v['channel'] and 'beta' in _ANDROID_PACKAGE_KEY)):
738             omaha = map(int, v['version'].split('.'))
739             device = map(int, self._driver.capabilities['version'].split('.'))
740             self.assertTrue(omaha <= device)
741             return
742       raise RuntimeError('Malformed omaha JSON')
743     except urllib2.URLError as e:
744       print 'Unable to fetch current version info from omahaproxy (%s)' % e
745
746   def testDeviceManagement(self):
747     self._drivers = [self.CreateDriver() for x in
748                      android_commands.GetAttachedDevices()]
749     self.assertRaises(chromedriver.UnknownError, self.CreateDriver)
750     self._drivers[0].Quit()
751     self._drivers[0] = self.CreateDriver()
752
753
754 class ChromeSwitchesCapabilityTest(ChromeDriverBaseTest):
755   """Tests that chromedriver properly processes chromeOptions.args capabilities.
756
757   Makes sure the switches are passed to Chrome.
758   """
759
760   def testSwitchWithoutArgument(self):
761     """Tests that switch --dom-automation can be passed to Chrome.
762
763     Unless --dom-automation is specified, window.domAutomationController
764     is undefined.
765     """
766     driver = self.CreateDriver(chrome_switches=['dom-automation'])
767     self.assertNotEqual(
768         None,
769         driver.ExecuteScript('return window.domAutomationController'))
770
771
772 class ChromeExtensionsCapabilityTest(ChromeDriverBaseTest):
773   """Tests that chromedriver properly processes chromeOptions.extensions."""
774
775   def _PackExtension(self, ext_path):
776     return base64.b64encode(open(ext_path, 'rb').read())
777
778   def testExtensionsInstall(self):
779     """Checks that chromedriver can take the extensions in crx format."""
780     crx_1 = os.path.join(_TEST_DATA_DIR, 'ext_test_1.crx')
781     crx_2 = os.path.join(_TEST_DATA_DIR, 'ext_test_2.crx')
782     self.CreateDriver(chrome_extensions=[self._PackExtension(crx_1),
783                                          self._PackExtension(crx_2)])
784
785   def testExtensionsInstallZip(self):
786     """Checks that chromedriver can take the extensions in zip format."""
787     zip_1 = os.path.join(_TEST_DATA_DIR, 'ext_test_1.zip')
788     self.CreateDriver(chrome_extensions=[self._PackExtension(zip_1)])
789
790   def testWaitsForExtensionToLoad(self):
791     did_load_event = threading.Event()
792     server = webserver.SyncWebServer()
793     def RunServer():
794       time.sleep(5)
795       server.RespondWithContent('<html>iframe</html>')
796       did_load_event.set()
797
798     thread = threading.Thread(target=RunServer)
799     thread.daemon = True
800     thread.start()
801     crx = os.path.join(_TEST_DATA_DIR, 'ext_slow_loader.crx')
802     driver = self.CreateDriver(
803         chrome_switches=['user-agent=' + server.GetUrl()],
804         chrome_extensions=[self._PackExtension(crx)])
805     self.assertTrue(did_load_event.is_set())
806
807
808 class ChromeLogPathCapabilityTest(ChromeDriverBaseTest):
809   """Tests that chromedriver properly processes chromeOptions.logPath."""
810
811   LOG_MESSAGE = 'Welcome to ChromeLogPathCapabilityTest!'
812
813   def testChromeLogPath(self):
814     """Checks that user can specify the path of the chrome log.
815
816     Verifies that a log message is written into the specified log file.
817     """
818     tmp_log_path = tempfile.NamedTemporaryFile()
819     driver = self.CreateDriver(chrome_log_path=tmp_log_path.name)
820     driver.ExecuteScript('console.info("%s")' % self.LOG_MESSAGE)
821     driver.Quit()
822     self.assertTrue(self.LOG_MESSAGE in open(tmp_log_path.name).read())
823
824
825 class MobileEmulationCapabilityTest(ChromeDriverBaseTest):
826   """Tests that ChromeDriver processes chromeOptions.mobileEmulation.
827
828   Makes sure the device metrics are overridden in DevTools and user agent is
829   overridden in Chrome.
830   """
831
832   @staticmethod
833   def GlobalSetUp():
834     def respondWithUserAgentString(request):
835       return request.GetHeader('User-Agent')
836
837     MobileEmulationCapabilityTest._http_server = webserver.WebServer(
838         chrome_paths.GetTestData())
839     MobileEmulationCapabilityTest._http_server.SetCallbackForPath(
840         '/userAgent', respondWithUserAgentString)
841
842   @staticmethod
843   def GlobalTearDown():
844     MobileEmulationCapabilityTest._http_server.Shutdown()
845
846   def testDeviceMetrics(self):
847     driver = self.CreateDriver(
848         mobile_emulation = {
849             'deviceMetrics': {'width': 360, 'height': 640, 'pixelRatio': 3}})
850     self.assertTrue(driver.capabilities['mobileEmulationEnabled'])
851     self.assertEqual(360, driver.ExecuteScript('return window.innerWidth'))
852     self.assertEqual(640, driver.ExecuteScript('return window.innerHeight'))
853
854   def testUserAgent(self):
855     driver = self.CreateDriver(
856         mobile_emulation = {'userAgent': 'Agent Smith'})
857     driver.Load(self._http_server.GetUrl() + '/userAgent')
858     body_tag = driver.FindElement('tag name', 'body')
859     self.assertEqual("Agent Smith", body_tag.GetText())
860
861   def testDeviceName(self):
862     driver = self.CreateDriver(
863         mobile_emulation = {'deviceName': 'Google Nexus 5'})
864     driver.Load(self._http_server.GetUrl() + '/userAgent')
865     self.assertEqual(360, driver.ExecuteScript('return window.innerWidth'))
866     self.assertEqual(640, driver.ExecuteScript('return window.innerHeight'))
867     body_tag = driver.FindElement('tag name', 'body')
868     self.assertEqual(
869         'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleW'
870         'ebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/53'
871         '5.19',
872         body_tag.GetText())
873
874
875 class ChromeDriverLogTest(unittest.TestCase):
876   """Tests that chromedriver produces the expected log file."""
877
878   UNEXPECTED_CHROMEOPTION_CAP = 'unexpected_chromeoption_capability'
879   LOG_MESSAGE = 'unrecognized chrome option: %s' % UNEXPECTED_CHROMEOPTION_CAP
880
881   def testChromeDriverLog(self):
882     _, tmp_log_path = tempfile.mkstemp(prefix='chromedriver_log_')
883     chromedriver_server = server.Server(
884         _CHROMEDRIVER_BINARY, log_path=tmp_log_path)
885     try:
886       driver = chromedriver.ChromeDriver(
887           chromedriver_server.GetUrl(), chrome_binary=_CHROME_BINARY,
888           experimental_options={ self.UNEXPECTED_CHROMEOPTION_CAP : 1 })
889       driver.Quit()
890     except chromedriver.ChromeDriverException, e:
891       self.assertTrue(self.LOG_MESSAGE in e.message)
892     finally:
893       chromedriver_server.Kill()
894     with open(tmp_log_path, 'r') as f:
895       self.assertTrue(self.LOG_MESSAGE in f.read())
896
897
898 class SessionHandlingTest(ChromeDriverBaseTest):
899   """Tests for session operations."""
900   def testQuitASessionMoreThanOnce(self):
901     driver = self.CreateDriver()
902     driver.Quit()
903     driver.Quit()
904
905
906 class RemoteBrowserTest(ChromeDriverBaseTest):
907   """Tests for ChromeDriver remote browser capability."""
908   def setUp(self):
909     self.assertTrue(_CHROME_BINARY is not None,
910                     'must supply a chrome binary arg')
911
912   def testConnectToRemoteBrowser(self):
913     port = self.FindFreePort()
914     temp_dir = util.MakeTempDir()
915     process = subprocess.Popen([_CHROME_BINARY,
916                                 '--remote-debugging-port=%d' % port,
917                                 '--user-data-dir=%s' % temp_dir])
918     if process is None:
919       raise RuntimeError('Chrome could not be started with debugging port')
920     try:
921       driver = self.CreateDriver(debugger_address='127.0.0.1:%d' % port)
922       driver.ExecuteScript('console.info("%s")' % 'connecting at %d!' % port)
923       driver.Quit()
924     finally:
925       process.terminate()
926
927   def FindFreePort(self):
928     for port in range(10000, 10100):
929       try:
930         socket.create_connection(('127.0.0.1', port), 0.2).close()
931       except socket.error:
932         return port
933     raise RuntimeError('Cannot find open port')
934
935 class PerfTest(ChromeDriverBaseTest):
936   """Tests for ChromeDriver perf."""
937   def setUp(self):
938     self.assertTrue(_REFERENCE_CHROMEDRIVER is not None,
939                     'must supply a reference-chromedriver arg')
940
941   def _RunDriverPerfTest(self, name, test_func):
942     """Runs a perf test comparing a reference and new ChromeDriver server.
943
944     Args:
945       name: The name of the perf test.
946       test_func: Called with the server url to perform the test action. Must
947                  return the time elapsed.
948     """
949     class Results(object):
950       ref = []
951       new = []
952
953     ref_server = server.Server(_REFERENCE_CHROMEDRIVER)
954     results = Results()
955     result_url_pairs = zip([results.new, results.ref],
956                            [_CHROMEDRIVER_SERVER_URL, ref_server.GetUrl()])
957     for iteration in range(30):
958       for result, url in result_url_pairs:
959         result += [test_func(url)]
960       # Reverse the order for the next run.
961       result_url_pairs = result_url_pairs[::-1]
962
963     def PrintResult(build, result):
964       mean = sum(result) / len(result)
965       avg_dev = sum([abs(sample - mean) for sample in result]) / len(result)
966       print 'perf result', build, name, mean, avg_dev, result
967       util.AddBuildStepText('%s %s: %.3f+-%.3f' % (
968           build, name, mean, avg_dev))
969
970     # Discard first result, which may be off due to cold start.
971     PrintResult('new', results.new[1:])
972     PrintResult('ref', results.ref[1:])
973
974   def testSessionStartTime(self):
975     def Run(url):
976       start = time.time()
977       driver = self.CreateDriver(url)
978       end = time.time()
979       driver.Quit()
980       return end - start
981     self._RunDriverPerfTest('session start', Run)
982
983   def testSessionStopTime(self):
984     def Run(url):
985       driver = self.CreateDriver(url)
986       start = time.time()
987       driver.Quit()
988       end = time.time()
989       return end - start
990     self._RunDriverPerfTest('session stop', Run)
991
992   def testColdExecuteScript(self):
993     def Run(url):
994       driver = self.CreateDriver(url)
995       start = time.time()
996       driver.ExecuteScript('return 1')
997       end = time.time()
998       driver.Quit()
999       return end - start
1000     self._RunDriverPerfTest('cold exe js', Run)
1001
1002 if __name__ == '__main__':
1003   parser = optparse.OptionParser()
1004   parser.add_option(
1005       '', '--chromedriver',
1006       help='Path to chromedriver server (REQUIRED!)')
1007   parser.add_option(
1008       '', '--log-path',
1009       help='Output verbose server logs to this file')
1010   parser.add_option(
1011       '', '--reference-chromedriver',
1012       help='Path to the reference chromedriver server')
1013   parser.add_option(
1014       '', '--chrome', help='Path to a build of the chrome binary')
1015   parser.add_option(
1016       '', '--chrome-version', default='HEAD',
1017       help='Version of chrome. Default is \'HEAD\'.')
1018   parser.add_option(
1019       '', '--filter', type='string', default='*',
1020       help=('Filter for specifying what tests to run, "*" will run all. E.g., '
1021             '*testStartStop'))
1022   parser.add_option(
1023       '', '--android-package',
1024       help=('Android package key. Possible values: ' +
1025             str(_ANDROID_NEGATIVE_FILTER.keys())))
1026   options, args = parser.parse_args()
1027
1028   options.chromedriver = util.GetAbsolutePathOfUserPath(options.chromedriver)
1029   if not options.chromedriver or not os.path.exists(options.chromedriver):
1030     parser.error('chromedriver is required or the given path is invalid.' +
1031                  'Please run "%s --help" for help' % __file__)
1032
1033   global _CHROMEDRIVER_BINARY
1034   _CHROMEDRIVER_BINARY = options.chromedriver
1035
1036   if (options.android_package and
1037       options.android_package not in _ANDROID_NEGATIVE_FILTER):
1038     parser.error('Invalid --android-package')
1039
1040   chromedriver_server = server.Server(_CHROMEDRIVER_BINARY, options.log_path)
1041   global _CHROMEDRIVER_SERVER_URL
1042   _CHROMEDRIVER_SERVER_URL = chromedriver_server.GetUrl()
1043
1044   global _REFERENCE_CHROMEDRIVER
1045   _REFERENCE_CHROMEDRIVER = util.GetAbsolutePathOfUserPath(
1046       options.reference_chromedriver)
1047
1048   global _CHROME_BINARY
1049   if options.chrome:
1050     _CHROME_BINARY = util.GetAbsolutePathOfUserPath(options.chrome)
1051   else:
1052     _CHROME_BINARY = None
1053
1054   global _ANDROID_PACKAGE_KEY
1055   _ANDROID_PACKAGE_KEY = options.android_package
1056
1057   if options.filter == '*':
1058     if _ANDROID_PACKAGE_KEY:
1059       negative_filter = _ANDROID_NEGATIVE_FILTER[_ANDROID_PACKAGE_KEY]
1060     else:
1061       negative_filter = _GetDesktopNegativeFilter(options.chrome_version)
1062     options.filter = '*-' + ':__main__.'.join([''] + negative_filter)
1063
1064   all_tests_suite = unittest.defaultTestLoader.loadTestsFromModule(
1065       sys.modules[__name__])
1066   tests = unittest_util.FilterTestSuite(all_tests_suite, options.filter)
1067   ChromeDriverTest.GlobalSetUp()
1068   MobileEmulationCapabilityTest.GlobalSetUp()
1069   result = unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(tests)
1070   ChromeDriverTest.GlobalTearDown()
1071   MobileEmulationCapabilityTest.GlobalTearDown()
1072   sys.exit(len(result.failures) + len(result.errors))