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