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 8import base64 9import json 10import math 11import optparse 12import os 13import socket 14import subprocess 15import sys 16import tempfile 17import threading 18import time 19import unittest 20import urllib2 21 22_THIS_DIR = os.path.abspath(os.path.dirname(__file__)) 23sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir)) 24sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir, 'client')) 25sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir, 'server')) 26 27import chrome_paths 28import chromedriver 29import unittest_util 30import util 31import server 32from webelement import WebElement 33import webserver 34 35_TEST_DATA_DIR = os.path.join(chrome_paths.GetTestData(), 'chromedriver') 36 37if 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 89def _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 141class 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 178class 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 719class 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 self.assertEquals(v['version'], 739 self._driver.capabilities['version']) 740 return 741 raise RuntimeError('Malformed omaha JSON') 742 except urllib2.URLError as e: 743 print 'Unable to fetch current version info from omahaproxy (%s)' % e 744 745 def testDeviceManagement(self): 746 self._drivers = [self.CreateDriver() for x in 747 android_commands.GetAttachedDevices()] 748 self.assertRaises(chromedriver.UnknownError, self.CreateDriver) 749 self._drivers[0].Quit() 750 self._drivers[0] = self.CreateDriver() 751 752 753class ChromeSwitchesCapabilityTest(ChromeDriverBaseTest): 754 """Tests that chromedriver properly processes chromeOptions.args capabilities. 755 756 Makes sure the switches are passed to Chrome. 757 """ 758 759 def testSwitchWithoutArgument(self): 760 """Tests that switch --dom-automation can be passed to Chrome. 761 762 Unless --dom-automation is specified, window.domAutomationController 763 is undefined. 764 """ 765 driver = self.CreateDriver(chrome_switches=['dom-automation']) 766 self.assertNotEqual( 767 None, 768 driver.ExecuteScript('return window.domAutomationController')) 769 770 771class ChromeExtensionsCapabilityTest(ChromeDriverBaseTest): 772 """Tests that chromedriver properly processes chromeOptions.extensions.""" 773 774 def _PackExtension(self, ext_path): 775 return base64.b64encode(open(ext_path, 'rb').read()) 776 777 def testExtensionsInstall(self): 778 """Checks that chromedriver can take the extensions in crx format.""" 779 crx_1 = os.path.join(_TEST_DATA_DIR, 'ext_test_1.crx') 780 crx_2 = os.path.join(_TEST_DATA_DIR, 'ext_test_2.crx') 781 self.CreateDriver(chrome_extensions=[self._PackExtension(crx_1), 782 self._PackExtension(crx_2)]) 783 784 def testExtensionsInstallZip(self): 785 """Checks that chromedriver can take the extensions in zip format.""" 786 zip_1 = os.path.join(_TEST_DATA_DIR, 'ext_test_1.zip') 787 self.CreateDriver(chrome_extensions=[self._PackExtension(zip_1)]) 788 789 def testWaitsForExtensionToLoad(self): 790 did_load_event = threading.Event() 791 server = webserver.SyncWebServer() 792 def RunServer(): 793 time.sleep(5) 794 server.RespondWithContent('<html>iframe</html>') 795 did_load_event.set() 796 797 thread = threading.Thread(target=RunServer) 798 thread.daemon = True 799 thread.start() 800 crx = os.path.join(_TEST_DATA_DIR, 'ext_slow_loader.crx') 801 driver = self.CreateDriver( 802 chrome_switches=['user-agent=' + server.GetUrl()], 803 chrome_extensions=[self._PackExtension(crx)]) 804 self.assertTrue(did_load_event.is_set()) 805 806 807class ChromeLogPathCapabilityTest(ChromeDriverBaseTest): 808 """Tests that chromedriver properly processes chromeOptions.logPath.""" 809 810 LOG_MESSAGE = 'Welcome to ChromeLogPathCapabilityTest!' 811 812 def testChromeLogPath(self): 813 """Checks that user can specify the path of the chrome log. 814 815 Verifies that a log message is written into the specified log file. 816 """ 817 tmp_log_path = tempfile.NamedTemporaryFile() 818 driver = self.CreateDriver(chrome_log_path=tmp_log_path.name) 819 driver.ExecuteScript('console.info("%s")' % self.LOG_MESSAGE) 820 driver.Quit() 821 self.assertTrue(self.LOG_MESSAGE in open(tmp_log_path.name).read()) 822 823 824class MobileEmulationCapabilityTest(ChromeDriverBaseTest): 825 """Tests that ChromeDriver processes chromeOptions.mobileEmulation. 826 827 Makes sure the device metrics are overridden in DevTools and user agent is 828 overridden in Chrome. 829 """ 830 831 @staticmethod 832 def GlobalSetUp(): 833 def respondWithUserAgentString(request): 834 return request.GetHeader('User-Agent') 835 836 MobileEmulationCapabilityTest._http_server = webserver.WebServer( 837 chrome_paths.GetTestData()) 838 MobileEmulationCapabilityTest._http_server.SetCallbackForPath( 839 '/userAgent', respondWithUserAgentString) 840 841 @staticmethod 842 def GlobalTearDown(): 843 MobileEmulationCapabilityTest._http_server.Shutdown() 844 845 def testDeviceMetrics(self): 846 driver = self.CreateDriver( 847 mobile_emulation = { 848 'deviceMetrics': {'width': 360, 'height': 640, 'pixelRatio': 3}}) 849 self.assertTrue(driver.capabilities['mobileEmulationEnabled']) 850 self.assertEqual(360, driver.ExecuteScript('return window.innerWidth')) 851 self.assertEqual(640, driver.ExecuteScript('return window.innerHeight')) 852 853 def testUserAgent(self): 854 driver = self.CreateDriver( 855 mobile_emulation = {'userAgent': 'Agent Smith'}) 856 driver.Load(self._http_server.GetUrl() + '/userAgent') 857 body_tag = driver.FindElement('tag name', 'body') 858 self.assertEqual("Agent Smith", body_tag.GetText()) 859 860 def testDeviceName(self): 861 driver = self.CreateDriver( 862 mobile_emulation = {'deviceName': 'Google Nexus 5'}) 863 driver.Load(self._http_server.GetUrl() + '/userAgent') 864 self.assertEqual(360, driver.ExecuteScript('return window.innerWidth')) 865 self.assertEqual(640, driver.ExecuteScript('return window.innerHeight')) 866 body_tag = driver.FindElement('tag name', 'body') 867 self.assertEqual( 868 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleW' 869 'ebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/53' 870 '5.19', 871 body_tag.GetText()) 872 873 874class ChromeDriverLogTest(unittest.TestCase): 875 """Tests that chromedriver produces the expected log file.""" 876 877 UNEXPECTED_CHROMEOPTION_CAP = 'unexpected_chromeoption_capability' 878 LOG_MESSAGE = 'unrecognized chrome option: %s' % UNEXPECTED_CHROMEOPTION_CAP 879 880 def testChromeDriverLog(self): 881 _, tmp_log_path = tempfile.mkstemp(prefix='chromedriver_log_') 882 chromedriver_server = server.Server( 883 _CHROMEDRIVER_BINARY, log_path=tmp_log_path) 884 try: 885 driver = chromedriver.ChromeDriver( 886 chromedriver_server.GetUrl(), chrome_binary=_CHROME_BINARY, 887 experimental_options={ self.UNEXPECTED_CHROMEOPTION_CAP : 1 }) 888 driver.Quit() 889 except chromedriver.ChromeDriverException, e: 890 self.assertTrue(self.LOG_MESSAGE in e.message) 891 finally: 892 chromedriver_server.Kill() 893 with open(tmp_log_path, 'r') as f: 894 self.assertTrue(self.LOG_MESSAGE in f.read()) 895 896 897class SessionHandlingTest(ChromeDriverBaseTest): 898 """Tests for session operations.""" 899 def testQuitASessionMoreThanOnce(self): 900 driver = self.CreateDriver() 901 driver.Quit() 902 driver.Quit() 903 904 905class RemoteBrowserTest(ChromeDriverBaseTest): 906 """Tests for ChromeDriver remote browser capability.""" 907 def setUp(self): 908 self.assertTrue(_CHROME_BINARY is not None, 909 'must supply a chrome binary arg') 910 911 def testConnectToRemoteBrowser(self): 912 port = self.FindFreePort() 913 temp_dir = util.MakeTempDir() 914 process = subprocess.Popen([_CHROME_BINARY, 915 '--remote-debugging-port=%d' % port, 916 '--user-data-dir=%s' % temp_dir]) 917 if process is None: 918 raise RuntimeError('Chrome could not be started with debugging port') 919 try: 920 driver = self.CreateDriver(debugger_address='127.0.0.1:%d' % port) 921 driver.ExecuteScript('console.info("%s")' % 'connecting at %d!' % port) 922 driver.Quit() 923 finally: 924 process.terminate() 925 926 def FindFreePort(self): 927 for port in range(10000, 10100): 928 try: 929 socket.create_connection(('127.0.0.1', port), 0.2).close() 930 except socket.error: 931 return port 932 raise RuntimeError('Cannot find open port') 933 934class PerfTest(ChromeDriverBaseTest): 935 """Tests for ChromeDriver perf.""" 936 def setUp(self): 937 self.assertTrue(_REFERENCE_CHROMEDRIVER is not None, 938 'must supply a reference-chromedriver arg') 939 940 def _RunDriverPerfTest(self, name, test_func): 941 """Runs a perf test comparing a reference and new ChromeDriver server. 942 943 Args: 944 name: The name of the perf test. 945 test_func: Called with the server url to perform the test action. Must 946 return the time elapsed. 947 """ 948 class Results(object): 949 ref = [] 950 new = [] 951 952 ref_server = server.Server(_REFERENCE_CHROMEDRIVER) 953 results = Results() 954 result_url_pairs = zip([results.new, results.ref], 955 [_CHROMEDRIVER_SERVER_URL, ref_server.GetUrl()]) 956 for iteration in range(30): 957 for result, url in result_url_pairs: 958 result += [test_func(url)] 959 # Reverse the order for the next run. 960 result_url_pairs = result_url_pairs[::-1] 961 962 def PrintResult(build, result): 963 mean = sum(result) / len(result) 964 avg_dev = sum([abs(sample - mean) for sample in result]) / len(result) 965 print 'perf result', build, name, mean, avg_dev, result 966 util.AddBuildStepText('%s %s: %.3f+-%.3f' % ( 967 build, name, mean, avg_dev)) 968 969 # Discard first result, which may be off due to cold start. 970 PrintResult('new', results.new[1:]) 971 PrintResult('ref', results.ref[1:]) 972 973 def testSessionStartTime(self): 974 def Run(url): 975 start = time.time() 976 driver = self.CreateDriver(url) 977 end = time.time() 978 driver.Quit() 979 return end - start 980 self._RunDriverPerfTest('session start', Run) 981 982 def testSessionStopTime(self): 983 def Run(url): 984 driver = self.CreateDriver(url) 985 start = time.time() 986 driver.Quit() 987 end = time.time() 988 return end - start 989 self._RunDriverPerfTest('session stop', Run) 990 991 def testColdExecuteScript(self): 992 def Run(url): 993 driver = self.CreateDriver(url) 994 start = time.time() 995 driver.ExecuteScript('return 1') 996 end = time.time() 997 driver.Quit() 998 return end - start 999 self._RunDriverPerfTest('cold exe js', Run) 1000 1001if __name__ == '__main__': 1002 parser = optparse.OptionParser() 1003 parser.add_option( 1004 '', '--chromedriver', 1005 help='Path to chromedriver server (REQUIRED!)') 1006 parser.add_option( 1007 '', '--log-path', 1008 help='Output verbose server logs to this file') 1009 parser.add_option( 1010 '', '--reference-chromedriver', 1011 help='Path to the reference chromedriver server') 1012 parser.add_option( 1013 '', '--chrome', help='Path to a build of the chrome binary') 1014 parser.add_option( 1015 '', '--chrome-version', default='HEAD', 1016 help='Version of chrome. Default is \'HEAD\'.') 1017 parser.add_option( 1018 '', '--filter', type='string', default='*', 1019 help=('Filter for specifying what tests to run, "*" will run all. E.g., ' 1020 '*testStartStop')) 1021 parser.add_option( 1022 '', '--android-package', 1023 help=('Android package key. Possible values: ' + 1024 str(_ANDROID_NEGATIVE_FILTER.keys()))) 1025 options, args = parser.parse_args() 1026 1027 options.chromedriver = util.GetAbsolutePathOfUserPath(options.chromedriver) 1028 if not options.chromedriver or not os.path.exists(options.chromedriver): 1029 parser.error('chromedriver is required or the given path is invalid.' + 1030 'Please run "%s --help" for help' % __file__) 1031 1032 global _CHROMEDRIVER_BINARY 1033 _CHROMEDRIVER_BINARY = options.chromedriver 1034 1035 if (options.android_package and 1036 options.android_package not in _ANDROID_NEGATIVE_FILTER): 1037 parser.error('Invalid --android-package') 1038 1039 chromedriver_server = server.Server(_CHROMEDRIVER_BINARY, options.log_path) 1040 global _CHROMEDRIVER_SERVER_URL 1041 _CHROMEDRIVER_SERVER_URL = chromedriver_server.GetUrl() 1042 1043 global _REFERENCE_CHROMEDRIVER 1044 _REFERENCE_CHROMEDRIVER = util.GetAbsolutePathOfUserPath( 1045 options.reference_chromedriver) 1046 1047 global _CHROME_BINARY 1048 if options.chrome: 1049 _CHROME_BINARY = util.GetAbsolutePathOfUserPath(options.chrome) 1050 else: 1051 _CHROME_BINARY = None 1052 1053 global _ANDROID_PACKAGE_KEY 1054 _ANDROID_PACKAGE_KEY = options.android_package 1055 1056 if options.filter == '*': 1057 if _ANDROID_PACKAGE_KEY: 1058 negative_filter = _ANDROID_NEGATIVE_FILTER[_ANDROID_PACKAGE_KEY] 1059 else: 1060 negative_filter = _GetDesktopNegativeFilter(options.chrome_version) 1061 options.filter = '*-' + ':__main__.'.join([''] + negative_filter) 1062 1063 all_tests_suite = unittest.defaultTestLoader.loadTestsFromModule( 1064 sys.modules[__name__]) 1065 tests = unittest_util.FilterTestSuite(all_tests_suite, options.filter) 1066 ChromeDriverTest.GlobalSetUp() 1067 MobileEmulationCapabilityTest.GlobalSetUp() 1068 result = unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(tests) 1069 ChromeDriverTest.GlobalTearDown() 1070 MobileEmulationCapabilityTest.GlobalTearDown() 1071 sys.exit(len(result.failures) + len(result.errors)) 1072