| #!/usr/bin/env python |
| # Copyright 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """End to end tests for ChromeDriver.""" |
| |
| import base64 |
| import optparse |
| import subprocess |
| import os |
| import sys |
| import socket |
| import tempfile |
| import threading |
| import time |
| import unittest |
| |
| _THIS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir)) |
| sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir, 'client')) |
| sys.path.insert(1, os.path.join(_THIS_DIR, os.pardir, 'server')) |
| |
| import chrome_paths |
| import chromedriver |
| import unittest_util |
| import util |
| import server |
| from webelement import WebElement |
| import webserver |
| |
| _TEST_DATA_DIR = os.path.join(chrome_paths.GetTestData(), 'chromedriver') |
| |
| if util.IsLinux(): |
| sys.path.insert(0, os.path.join(chrome_paths.GetSrc(), 'build', 'android')) |
| from pylib import android_commands |
| from pylib import forwarder |
| from pylib import valgrind_tools |
| |
| |
| _NEGATIVE_FILTER = {} |
| _NEGATIVE_FILTER['HEAD'] = [ |
| # https://code.google.com/p/chromedriver/issues/detail?id=213 |
| 'ChromeDriverTest.testClickElementInSubFrame', |
| # This test is flaky since it uses setTimeout. |
| # Re-enable once crbug.com/177511 is fixed and we can remove setTimeout. |
| 'ChromeDriverTest.testAlert', |
| ] |
| |
| _DESKTOP_OS_SPECIFIC_FILTER = [] |
| if util.IsWindows(): |
| _DESKTOP_OS_SPECIFIC_FILTER = [ |
| # https://code.google.com/p/chromedriver/issues/detail?id=214 |
| 'ChromeDriverTest.testCloseWindow', |
| # https://code.google.com/p/chromedriver/issues/detail?id=299 |
| 'ChromeLogPathCapabilityTest.testChromeLogPath', |
| ] |
| elif util.IsLinux(): |
| _DESKTOP_OS_SPECIFIC_FILTER = [ |
| # Xvfb doesn't support maximization. |
| 'ChromeDriverTest.testWindowMaximize', |
| # https://code.google.com/p/chromedriver/issues/detail?id=302 |
| 'ChromeDriverTest.testWindowPosition', |
| 'ChromeDriverTest.testWindowSize', |
| ] |
| elif util.IsMac(): |
| _DESKTOP_OS_SPECIFIC_FILTER = [ |
| # https://code.google.com/p/chromedriver/issues/detail?id=304 |
| 'ChromeDriverTest.testGoBackAndGoForward', |
| ] |
| |
| |
| _DESKTOP_NEGATIVE_FILTER = {} |
| _DESKTOP_NEGATIVE_FILTER['HEAD'] = ( |
| _NEGATIVE_FILTER['HEAD'] + |
| _DESKTOP_OS_SPECIFIC_FILTER + [ |
| # Desktop doesn't support touch (without --touch-events). |
| 'ChromeDriverTest.testSingleTapElement', |
| 'ChromeDriverTest.testTouchDownUpElement', |
| 'ChromeDriverTest.testTouchMovedElement', |
| ] |
| ) |
| |
| |
| def _GetDesktopNegativeFilter(version_name): |
| if version_name in _DESKTOP_NEGATIVE_FILTER: |
| return _DESKTOP_NEGATIVE_FILTER[version_name] |
| return _DESKTOP_NEGATIVE_FILTER['HEAD'] |
| |
| |
| _ANDROID_NEGATIVE_FILTER = {} |
| _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] = ( |
| _NEGATIVE_FILTER['HEAD'] + [ |
| # TODO(chrisgao): fix hang of tab crash test on android. |
| 'ChromeDriverTest.testTabCrash', |
| # Android doesn't support switches and extensions. |
| 'ChromeSwitchesCapabilityTest.*', |
| 'ChromeExtensionsCapabilityTest.*', |
| # https://crbug.com/274650 |
| 'ChromeDriverTest.testCloseWindow', |
| # https://code.google.com/p/chromedriver/issues/detail?id=270 |
| 'ChromeDriverTest.testPopups', |
| # https://code.google.com/p/chromedriver/issues/detail?id=298 |
| 'ChromeDriverTest.testWindowPosition', |
| 'ChromeDriverTest.testWindowSize', |
| 'ChromeDriverTest.testWindowMaximize', |
| 'ChromeLogPathCapabilityTest.testChromeLogPath', |
| 'ExistingBrowserTest.*', |
| # Don't enable perf testing on Android yet. |
| 'PerfTest.testSessionStartTime', |
| 'PerfTest.testSessionStopTime', |
| 'PerfTest.testColdExecuteScript', |
| ] |
| ) |
| _ANDROID_NEGATIVE_FILTER['com.android.chrome'] = ( |
| _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome']) |
| _ANDROID_NEGATIVE_FILTER['com.chrome.beta'] = ( |
| _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome']) |
| _ANDROID_NEGATIVE_FILTER['org.chromium.chrome.testshell'] = ( |
| _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] + [ |
| # ChromiumTestShell doesn't support multiple tabs. |
| 'ChromeDriverTest.testGetWindowHandles', |
| 'ChromeDriverTest.testSwitchToWindow', |
| 'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly', |
| ] |
| ) |
| |
| |
| class ChromeDriverBaseTest(unittest.TestCase): |
| """Base class for testing chromedriver functionalities.""" |
| |
| def __init__(self, *args, **kwargs): |
| super(ChromeDriverBaseTest, self).__init__(*args, **kwargs) |
| self._drivers = [] |
| |
| def tearDown(self): |
| for driver in self._drivers: |
| try: |
| driver.Quit() |
| except: |
| pass |
| |
| def CreateDriver(self, server_url=None, **kwargs): |
| if server_url is None: |
| server_url = _CHROMEDRIVER_SERVER_URL |
| driver = chromedriver.ChromeDriver(server_url, |
| chrome_binary=_CHROME_BINARY, |
| android_package=_ANDROID_PACKAGE, |
| **kwargs) |
| self._drivers += [driver] |
| return driver |
| |
| |
| class ChromeDriverTest(ChromeDriverBaseTest): |
| """End to end tests for ChromeDriver.""" |
| |
| @staticmethod |
| def GlobalSetUp(): |
| ChromeDriverTest._http_server = webserver.WebServer( |
| chrome_paths.GetTestData()) |
| ChromeDriverTest._sync_server = webserver.SyncWebServer() |
| if _ANDROID_PACKAGE: |
| ChromeDriverTest._adb = android_commands.AndroidCommands() |
| http_host_port = ChromeDriverTest._http_server._server.server_port |
| sync_host_port = ChromeDriverTest._sync_server._server.server_port |
| forwarder.Forwarder.Map( |
| [(http_host_port, http_host_port), (sync_host_port, sync_host_port)], |
| ChromeDriverTest._adb) |
| |
| @staticmethod |
| def GlobalTearDown(): |
| if _ANDROID_PACKAGE: |
| forwarder.Forwarder.UnmapAllDevicePorts(ChromeDriverTest._adb) |
| ChromeDriverTest._http_server.Shutdown() |
| |
| @staticmethod |
| def GetHttpUrlForFile(file_path): |
| return ChromeDriverTest._http_server.GetUrl() + file_path |
| |
| def setUp(self): |
| self._driver = self.CreateDriver() |
| |
| def testStartStop(self): |
| pass |
| |
| def testLoadUrl(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| |
| def testGetCurrentWindowHandle(self): |
| self._driver.GetCurrentWindowHandle() |
| |
| def _WaitForNewWindow(self, old_handles): |
| """Wait for at least one new window to show up in 20 seconds. |
| |
| Args: |
| old_handles: Handles to all old windows before the new window is added. |
| |
| Returns: |
| Handle to a new window. None if timeout. |
| """ |
| timeout = time.time() + 20 |
| while time.time() < timeout: |
| new_handles = self._driver.GetWindowHandles() |
| if len(new_handles) > len(old_handles): |
| for index, old_handle in enumerate(old_handles): |
| self.assertEquals(old_handle, new_handles[index]) |
| return new_handles[len(old_handles)] |
| time.sleep(0.01) |
| return None |
| |
| def testCloseWindow(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('id', 'link').Click() |
| new_window_handle = self._WaitForNewWindow(old_handles) |
| self.assertNotEqual(None, new_window_handle) |
| self._driver.SwitchToWindow(new_window_handle) |
| self.assertEquals(new_window_handle, self._driver.GetCurrentWindowHandle()) |
| self.assertRaises(chromedriver.NoSuchElement, |
| self._driver.FindElement, 'id', 'link') |
| self._driver.CloseWindow() |
| self.assertRaises(chromedriver.NoSuchWindow, |
| self._driver.GetCurrentWindowHandle) |
| new_handles = self._driver.GetWindowHandles() |
| for old_handle in old_handles: |
| self.assertTrue(old_handle in new_handles) |
| for handle in new_handles: |
| self._driver.SwitchToWindow(handle) |
| self.assertEquals(handle, self._driver.GetCurrentWindowHandle()) |
| self._driver.CloseWindow() |
| |
| def testGetWindowHandles(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('id', 'link').Click() |
| self.assertNotEqual(None, self._WaitForNewWindow(old_handles)) |
| |
| def testSwitchToWindow(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| self.assertEquals( |
| 1, self._driver.ExecuteScript('window.name = "oldWindow"; return 1;')) |
| window1_handle = self._driver.GetCurrentWindowHandle() |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('id', 'link').Click() |
| new_window_handle = self._WaitForNewWindow(old_handles) |
| self.assertNotEqual(None, new_window_handle) |
| self._driver.SwitchToWindow(new_window_handle) |
| self.assertEquals(new_window_handle, self._driver.GetCurrentWindowHandle()) |
| self.assertRaises(chromedriver.NoSuchElement, |
| self._driver.FindElement, 'id', 'link') |
| self._driver.SwitchToWindow('oldWindow') |
| self.assertEquals(window1_handle, self._driver.GetCurrentWindowHandle()) |
| |
| def testEvaluateScript(self): |
| self.assertEquals(1, self._driver.ExecuteScript('return 1')) |
| self.assertEquals(None, self._driver.ExecuteScript('')) |
| |
| def testEvaluateScriptWithArgs(self): |
| script = ('document.body.innerHTML = "<div>b</div><div>c</div>";' |
| 'return {stuff: document.querySelectorAll("div")};') |
| stuff = self._driver.ExecuteScript(script)['stuff'] |
| script = 'return arguments[0].innerHTML + arguments[1].innerHTML' |
| self.assertEquals( |
| 'bc', self._driver.ExecuteScript(script, stuff[0], stuff[1])) |
| |
| def testEvaluateInvalidScript(self): |
| self.assertRaises(chromedriver.ChromeDriverException, |
| self._driver.ExecuteScript, '{{{') |
| |
| def testExecuteAsyncScript(self): |
| self._driver.SetTimeout('script', 3000) |
| self.assertRaises( |
| chromedriver.ScriptTimeout, |
| self._driver.ExecuteAsyncScript, |
| 'var callback = arguments[0];' |
| 'setTimeout(function(){callback(1);}, 10000);') |
| self.assertEquals( |
| 2, |
| self._driver.ExecuteAsyncScript( |
| 'var callback = arguments[0];' |
| 'setTimeout(function(){callback(2);}, 300);')) |
| |
| def testSwitchToFrame(self): |
| self._driver.ExecuteScript( |
| 'var frame = document.createElement("iframe");' |
| 'frame.id="id";' |
| 'frame.name="name";' |
| 'document.body.appendChild(frame);') |
| self.assertTrue(self._driver.ExecuteScript('return window.top == window')) |
| self._driver.SwitchToFrame('id') |
| self.assertTrue(self._driver.ExecuteScript('return window.top != window')) |
| self._driver.SwitchToMainFrame() |
| self.assertTrue(self._driver.ExecuteScript('return window.top == window')) |
| self._driver.SwitchToFrame('name') |
| self.assertTrue(self._driver.ExecuteScript('return window.top != window')) |
| self._driver.SwitchToMainFrame() |
| self.assertTrue(self._driver.ExecuteScript('return window.top == window')) |
| self._driver.SwitchToFrameByIndex(0) |
| self.assertTrue(self._driver.ExecuteScript('return window.top != window')) |
| self._driver.SwitchToMainFrame() |
| self.assertTrue(self._driver.ExecuteScript('return window.top == window')) |
| self._driver.SwitchToFrame(self._driver.FindElement('tag name', 'iframe')) |
| self.assertTrue(self._driver.ExecuteScript('return window.top != window')) |
| |
| def testExecuteInRemovedFrame(self): |
| self._driver.ExecuteScript( |
| 'var frame = document.createElement("iframe");' |
| 'frame.id="id";' |
| 'frame.name="name";' |
| 'document.body.appendChild(frame);' |
| 'window.addEventListener("message",' |
| ' function(event) { document.body.removeChild(frame); });') |
| self.assertTrue(self._driver.ExecuteScript('return window.top == window')) |
| self._driver.SwitchToFrame('id') |
| self.assertTrue(self._driver.ExecuteScript('return window.top != window')) |
| self._driver.ExecuteScript('parent.postMessage("remove", "*");') |
| self.assertTrue(self._driver.ExecuteScript('return window.top == window')) |
| |
| def testGetTitle(self): |
| script = 'document.title = "title"; return 1;' |
| self.assertEquals(1, self._driver.ExecuteScript(script)) |
| self.assertEquals('title', self._driver.GetTitle()) |
| |
| def testGetPageSource(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| self.assertTrue('Link to empty.html' in self._driver.GetPageSource()) |
| |
| def testFindElement(self): |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>a</div><div>b</div>";') |
| self.assertTrue( |
| isinstance(self._driver.FindElement('tag name', 'div'), WebElement)) |
| |
| def testFindElements(self): |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>a</div><div>b</div>";') |
| divs = self._driver.FindElements('tag name', 'div') |
| self.assertTrue(isinstance(divs, list)) |
| self.assertEquals(2, len(divs)) |
| for div in divs: |
| self.assertTrue(isinstance(div, WebElement)) |
| |
| def testFindChildElement(self): |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div><br><br></div><div><a></a></div>";') |
| element = self._driver.FindElement('tag name', 'div') |
| self.assertTrue( |
| isinstance(element.FindElement('tag name', 'br'), WebElement)) |
| |
| def testFindChildElements(self): |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div><br><br></div><div><br></div>";') |
| element = self._driver.FindElement('tag name', 'div') |
| brs = element.FindElements('tag name', 'br') |
| self.assertTrue(isinstance(brs, list)) |
| self.assertEquals(2, len(brs)) |
| for br in brs: |
| self.assertTrue(isinstance(br, WebElement)) |
| |
| def testHoverOverElement(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.addEventListener("mouseover", function() {' |
| ' document.body.appendChild(document.createElement("br"));' |
| '});' |
| 'return div;') |
| div.HoverOver() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testClickElement(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.addEventListener("click", function() {' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| div.Click() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testSingleTapElement(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.addEventListener("touchend", function() {' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| div.SingleTap() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testTouchDownUpElement(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.addEventListener("touchend", function() {' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| loc = div.GetLocation() |
| self._driver.TouchDown(loc['x'], loc['y']) |
| self._driver.TouchUp(loc['x'], loc['y']) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testTouchMovedElement(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.addEventListener("touchmove", function() {' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| loc = div.GetLocation() |
| self._driver.TouchDown(loc['x'], loc['y']) |
| self._driver.TouchMove(loc['x'] + 1, loc['y'] + 1) |
| self._driver.TouchUp(loc['x'] + 1, loc['y'] + 1) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testClickElementInSubFrame(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/frame_test.html')) |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame) |
| # Test clicking element in the sub frame. |
| self.testClickElement() |
| |
| def testClearElement(self): |
| text = self._driver.ExecuteScript( |
| 'document.body.innerHTML = \'<input type="text" value="abc">\';' |
| 'var input = document.getElementsByTagName("input")[0];' |
| 'input.addEventListener("change", function() {' |
| ' document.body.appendChild(document.createElement("br"));' |
| '});' |
| 'return input;') |
| text.Clear() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testSendKeysToElement(self): |
| text = self._driver.ExecuteScript( |
| 'document.body.innerHTML = \'<input type="text">\';' |
| 'var input = document.getElementsByTagName("input")[0];' |
| 'input.addEventListener("change", function() {' |
| ' document.body.appendChild(document.createElement("br"));' |
| '});' |
| 'return input;') |
| text.SendKeys('0123456789+-*/ Hi') |
| text.SendKeys(', there!') |
| value = self._driver.ExecuteScript('return arguments[0].value;', text) |
| self.assertEquals('0123456789+-*/ Hi, there!', value) |
| |
| def testGetCurrentUrl(self): |
| self.assertTrue('data:,' in self._driver.GetCurrentUrl()) |
| |
| def testGoBackAndGoForward(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.GoBack() |
| self._driver.GoForward() |
| |
| def testRefresh(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.Refresh() |
| |
| def testMouseMoveTo(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.style["width"] = "100px";' |
| 'div.style["height"] = "100px";' |
| 'div.addEventListener("mouseover", function() {' |
| ' var div = document.getElementsByTagName("div")[0];' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| self._driver.MouseMoveTo(div, 10, 10) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testMouseClick(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.style["width"] = "100px";' |
| 'div.style["height"] = "100px";' |
| 'div.addEventListener("click", function() {' |
| ' var div = document.getElementsByTagName("div")[0];' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| self._driver.MouseMoveTo(div) |
| self._driver.MouseClick() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testMouseButtonDownAndUp(self): |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.style["width"] = "100px";' |
| 'div.style["height"] = "100px";' |
| 'div.addEventListener("mousedown", function() {' |
| ' var div = document.getElementsByTagName("div")[0];' |
| ' div.innerHTML="new1<br>";' |
| '});' |
| 'div.addEventListener("mouseup", function() {' |
| ' var div = document.getElementsByTagName("div")[0];' |
| ' div.innerHTML="new2<a></a>";' |
| '});') |
| self._driver.MouseMoveTo(None, 50, 50) |
| self._driver.MouseButtonDown() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| self._driver.MouseButtonUp() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'a'))) |
| |
| def testMouseDoubleClick(self): |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.style["width"] = "100px";' |
| 'div.style["height"] = "100px";' |
| 'div.addEventListener("dblclick", function() {' |
| ' var div = document.getElementsByTagName("div")[0];' |
| ' div.innerHTML="new<br>";' |
| '});' |
| 'return div;') |
| self._driver.MouseMoveTo(div, 1, 1) |
| self._driver.MouseDoubleClick() |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testAlert(self): |
| self.assertFalse(self._driver.IsAlertOpen()) |
| self._driver.ExecuteScript( |
| 'window.setTimeout(' |
| ' function() { window.confirmed = confirm(\'HI\'); },' |
| ' 0);') |
| self.assertTrue(self._driver.IsAlertOpen()) |
| self.assertEquals('HI', self._driver.GetAlertMessage()) |
| self._driver.HandleAlert(False) |
| self.assertFalse(self._driver.IsAlertOpen()) |
| self.assertEquals(False, |
| self._driver.ExecuteScript('return window.confirmed')) |
| |
| def testShouldHandleNewWindowLoadingProperly(self): |
| """Tests that ChromeDriver determines loading correctly for new windows.""" |
| self._http_server.SetDataForPath( |
| '/newwindow', |
| """ |
| <html> |
| <body> |
| <a href='%s' target='_blank'>new window/tab</a> |
| </body> |
| </html>""" % self._sync_server.GetUrl()) |
| self._driver.Load(self._http_server.GetUrl() + '/newwindow') |
| old_windows = self._driver.GetWindowHandles() |
| self._driver.FindElement('tagName', 'a').Click() |
| new_window = self._WaitForNewWindow(old_windows) |
| self.assertNotEqual(None, new_window) |
| |
| self.assertFalse(self._driver.IsLoading()) |
| self._driver.SwitchToWindow(new_window) |
| self.assertTrue(self._driver.IsLoading()) |
| self._sync_server.RespondWithContent('<html>new window</html>') |
| self._driver.ExecuteScript('return 1') # Shouldn't hang. |
| |
| def testPopups(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.ExecuteScript('window.open("about:blank")') |
| new_window_handle = self._WaitForNewWindow(old_handles) |
| self.assertNotEqual(None, new_window_handle) |
| |
| def testNoSuchFrame(self): |
| self.assertRaises(chromedriver.NoSuchFrame, |
| self._driver.SwitchToFrame, 'nosuchframe') |
| self.assertRaises(chromedriver.NoSuchFrame, |
| self._driver.SwitchToFrame, |
| self._driver.FindElement('tagName', 'body')) |
| |
| def testWindowPosition(self): |
| position = self._driver.GetWindowPosition() |
| self._driver.SetWindowPosition(position[0], position[1]) |
| self.assertEquals(position, self._driver.GetWindowPosition()) |
| |
| # Resize so the window isn't moved offscreen. |
| # See https://code.google.com/p/chromedriver/issues/detail?id=297. |
| self._driver.SetWindowSize(300, 300) |
| |
| self._driver.SetWindowPosition(100, 200) |
| self.assertEquals([100, 200], self._driver.GetWindowPosition()) |
| |
| def testWindowSize(self): |
| size = self._driver.GetWindowSize() |
| self._driver.SetWindowSize(size[0], size[1]) |
| self.assertEquals(size, self._driver.GetWindowSize()) |
| |
| self._driver.SetWindowSize(600, 400) |
| self.assertEquals([600, 400], self._driver.GetWindowSize()) |
| |
| def testWindowMaximize(self): |
| self._driver.SetWindowPosition(100, 200) |
| self._driver.SetWindowSize(600, 400) |
| self._driver.MaximizeWindow() |
| |
| self.assertNotEqual([100, 200], self._driver.GetWindowPosition()) |
| self.assertNotEqual([600, 400], self._driver.GetWindowSize()) |
| # Set size first so that the window isn't moved offscreen. |
| # See https://code.google.com/p/chromedriver/issues/detail?id=297. |
| self._driver.SetWindowSize(600, 400) |
| self._driver.SetWindowPosition(100, 200) |
| self.assertEquals([100, 200], self._driver.GetWindowPosition()) |
| self.assertEquals([600, 400], self._driver.GetWindowSize()) |
| |
| def testConsoleLogSources(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/console_log.html')) |
| logs = self._driver.GetLog('browser') |
| self.assertEquals(len(logs), 2) |
| self.assertEquals(logs[0]['source'], 'network') |
| self.assertEquals(logs[1]['source'], 'javascript') |
| |
| def testContextMenuEventFired(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/context_menu.html')) |
| self._driver.MouseMoveTo(self._driver.FindElement('tagName', 'div')) |
| self._driver.MouseClick(2) |
| self.assertTrue(self._driver.ExecuteScript('return success')) |
| |
| def testHasFocusOnStartup(self): |
| # Some pages (about:blank) cause Chrome to put the focus in URL bar. |
| # This breaks tests depending on focus. |
| self.assertTrue(self._driver.ExecuteScript('return document.hasFocus()')) |
| |
| def testTabCrash(self): |
| # If a tab is crashed, the session will be deleted. |
| # When 31 is released, will reload the tab instead. |
| # https://code.google.com/p/chromedriver/issues/detail?id=547 |
| self.assertRaises(chromedriver.UnknownError, |
| self._driver.Load, 'chrome://crash') |
| self.assertRaises(chromedriver.NoSuchSession, |
| self._driver.GetCurrentUrl) |
| |
| def testDoesntHangOnDebugger(self): |
| self._driver.ExecuteScript('debugger;') |
| |
| |
| class ChromeSwitchesCapabilityTest(ChromeDriverBaseTest): |
| """Tests that chromedriver properly processes chromeOptions.args capabilities. |
| |
| Makes sure the switches are passed to Chrome. |
| """ |
| |
| def testSwitchWithoutArgument(self): |
| """Tests that switch --dom-automation can be passed to Chrome. |
| |
| Unless --dom-automation is specified, window.domAutomationController |
| is undefined. |
| """ |
| driver = self.CreateDriver(chrome_switches=['dom-automation']) |
| self.assertNotEqual( |
| None, |
| driver.ExecuteScript('return window.domAutomationController')) |
| |
| |
| class ChromeExtensionsCapabilityTest(ChromeDriverBaseTest): |
| """Tests that chromedriver properly processes chromeOptions.extensions.""" |
| |
| def _PackExtension(self, ext_path): |
| return base64.b64encode(open(ext_path, 'rb').read()) |
| |
| def testExtensionsInstall(self): |
| """Checks that chromedriver can take the extensions.""" |
| crx_1 = os.path.join(_TEST_DATA_DIR, 'ext_test_1.crx') |
| crx_2 = os.path.join(_TEST_DATA_DIR, 'ext_test_2.crx') |
| self.CreateDriver(chrome_extensions=[self._PackExtension(crx_1), |
| self._PackExtension(crx_2)]) |
| |
| def testWaitsForExtensionToLoad(self): |
| did_load_event = threading.Event() |
| server = webserver.SyncWebServer() |
| def RunServer(): |
| time.sleep(5) |
| server.RespondWithContent('<html>iframe</html>') |
| did_load_event.set() |
| |
| thread = threading.Thread(target=RunServer) |
| thread.daemon = True |
| thread.start() |
| crx = os.path.join(_TEST_DATA_DIR, 'ext_slow_loader.crx') |
| driver = self.CreateDriver( |
| chrome_switches=['user-agent=' + server.GetUrl()], |
| chrome_extensions=[self._PackExtension(crx)]) |
| self.assertTrue(did_load_event.is_set()) |
| |
| |
| class ChromeLogPathCapabilityTest(ChromeDriverBaseTest): |
| """Tests that chromedriver properly processes chromeOptions.logPath.""" |
| |
| LOG_MESSAGE = 'Welcome to ChromeLogPathCapabilityTest!' |
| |
| def testChromeLogPath(self): |
| """Checks that user can specify the path of the chrome log. |
| |
| Verifies that a log message is written into the specified log file. |
| """ |
| tmp_log_path = tempfile.NamedTemporaryFile() |
| driver = self.CreateDriver(chrome_log_path=tmp_log_path.name) |
| driver.ExecuteScript('console.info("%s")' % self.LOG_MESSAGE) |
| driver.Quit() |
| self.assertTrue(self.LOG_MESSAGE in open(tmp_log_path.name).read()) |
| |
| |
| class SessionHandlingTest(ChromeDriverBaseTest): |
| """Tests for session operations.""" |
| def testQuitASessionMoreThanOnce(self): |
| driver = self.CreateDriver() |
| driver.Quit() |
| driver.Quit() |
| |
| |
| class ExistingBrowserTest(ChromeDriverBaseTest): |
| """Tests for ChromeDriver existing browser capability.""" |
| def setUp(self): |
| self.assertTrue(_CHROME_BINARY is not None, |
| 'must supply a chrome binary arg') |
| |
| def testConnectToExistingBrowser(self): |
| port = self.FindFreePort() |
| temp_dir = util.MakeTempDir() |
| process = subprocess.Popen([_CHROME_BINARY, |
| '--remote-debugging-port=%d' % port, |
| '--user-data-dir=%s' % temp_dir]) |
| if process is None: |
| raise RuntimeError('Chrome could not be started with debugging port') |
| try: |
| driver = self.CreateDriver(debugger_address='127.0.0.1:%d' % port) |
| driver.ExecuteScript('console.info("%s")' % 'connecting at %d!' % port) |
| driver.Quit() |
| finally: |
| process.terminate() |
| |
| def FindFreePort(self): |
| for port in range(10000, 10100): |
| try: |
| socket.create_connection(('127.0.0.1', port), 0.2).close() |
| except socket.error: |
| return port |
| raise RuntimeError('Cannot find open port') |
| |
| class PerfTest(ChromeDriverBaseTest): |
| """Tests for ChromeDriver perf.""" |
| def setUp(self): |
| self.assertTrue(_REFERENCE_CHROMEDRIVER is not None, |
| 'must supply a reference-chromedriver arg') |
| |
| def _RunDriverPerfTest(self, name, test_func): |
| """Runs a perf test comparing a reference and new ChromeDriver server. |
| |
| Args: |
| name: The name of the perf test. |
| test_func: Called with the server url to perform the test action. Must |
| return the time elapsed. |
| """ |
| class Results(object): |
| ref = [] |
| new = [] |
| |
| ref_server = server.Server(_REFERENCE_CHROMEDRIVER) |
| results = Results() |
| result_url_pairs = zip([results.new, results.ref], |
| [_CHROMEDRIVER_SERVER_URL, ref_server.GetUrl()]) |
| for iteration in range(30): |
| for result, url in result_url_pairs: |
| result += [test_func(url)] |
| # Reverse the order for the next run. |
| result_url_pairs = result_url_pairs[::-1] |
| |
| def PrintResult(build, result): |
| mean = sum(result) / len(result) |
| avg_dev = sum([abs(sample - mean) for sample in result]) / len(result) |
| print 'perf result', build, name, mean, avg_dev, result |
| util.AddBuildStepText('%s %s: %.3f+-%.3f' % ( |
| build, name, mean, avg_dev)) |
| |
| # Discard first result, which may be off due to cold start. |
| PrintResult('new', results.new[1:]) |
| PrintResult('ref', results.ref[1:]) |
| |
| def testSessionStartTime(self): |
| def Run(url): |
| start = time.time() |
| driver = self.CreateDriver(url) |
| end = time.time() |
| driver.Quit() |
| return end - start |
| self._RunDriverPerfTest('session start', Run) |
| |
| def testSessionStopTime(self): |
| def Run(url): |
| driver = self.CreateDriver(url) |
| start = time.time() |
| driver.Quit() |
| end = time.time() |
| return end - start |
| self._RunDriverPerfTest('session stop', Run) |
| |
| def testColdExecuteScript(self): |
| def Run(url): |
| driver = self.CreateDriver(url) |
| start = time.time() |
| driver.ExecuteScript('return 1') |
| end = time.time() |
| driver.Quit() |
| return end - start |
| self._RunDriverPerfTest('cold exe js', Run) |
| |
| if __name__ == '__main__': |
| parser = optparse.OptionParser() |
| parser.add_option( |
| '', '--chromedriver', |
| help='Path to chromedriver server (REQUIRED!)') |
| parser.add_option( |
| '', '--log-path', |
| help='Output verbose server logs to this file') |
| parser.add_option( |
| '', '--reference-chromedriver', |
| help='Path to the reference chromedriver server') |
| parser.add_option( |
| '', '--chrome', help='Path to a build of the chrome binary') |
| parser.add_option( |
| '', '--chrome-version', default='HEAD', |
| help='Version of chrome. Default is \'HEAD\'.') |
| parser.add_option( |
| '', '--filter', type='string', default='*', |
| help=('Filter for specifying what tests to run, "*" will run all. E.g., ' |
| '*testStartStop')) |
| parser.add_option( |
| '', '--android-package', help='Android package name') |
| options, args = parser.parse_args() |
| |
| if not options.chromedriver or not os.path.exists(options.chromedriver): |
| parser.error('chromedriver is required or the given path is invalid.' + |
| 'Please run "%s --help" for help' % __file__) |
| |
| chromedriver_server = server.Server(os.path.abspath(options.chromedriver), |
| options.log_path) |
| global _CHROMEDRIVER_SERVER_URL |
| _CHROMEDRIVER_SERVER_URL = chromedriver_server.GetUrl() |
| |
| global _REFERENCE_CHROMEDRIVER |
| _REFERENCE_CHROMEDRIVER = options.reference_chromedriver |
| |
| global _CHROME_BINARY |
| if options.chrome: |
| _CHROME_BINARY = os.path.abspath(options.chrome) |
| else: |
| _CHROME_BINARY = None |
| |
| global _ANDROID_PACKAGE |
| _ANDROID_PACKAGE = options.android_package |
| |
| if options.filter == '*': |
| if _ANDROID_PACKAGE: |
| negative_filter = _ANDROID_NEGATIVE_FILTER[_ANDROID_PACKAGE] |
| else: |
| negative_filter = _GetDesktopNegativeFilter(options.chrome_version) |
| options.filter = '*-' + ':__main__.'.join([''] + negative_filter) |
| |
| all_tests_suite = unittest.defaultTestLoader.loadTestsFromModule( |
| sys.modules[__name__]) |
| tests = unittest_util.FilterTestSuite(all_tests_suite, options.filter) |
| ChromeDriverTest.GlobalSetUp() |
| result = unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(tests) |
| ChromeDriverTest.GlobalTearDown() |
| sys.exit(len(result.failures) + len(result.errors)) |