| #!/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.""" |
| |
| # Note that to run Android tests you must have the following line in |
| # .gclient (in the parent directory of src): target_os = [ 'android' ] |
| # to get the appropriate adb version for ChromeDriver. |
| # TODO (crbug.com/857239): Remove above comment when adb version |
| # is updated in Devil. |
| |
| import base64 |
| import json |
| import math |
| import optparse |
| import os |
| import re |
| import shutil |
| import socket |
| import subprocess |
| import sys |
| import tempfile |
| import threading |
| import time |
| import unittest |
| import urllib |
| import urllib2 |
| import uuid |
| |
| |
| _THIS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| _PARENT_DIR = os.path.join(_THIS_DIR, os.pardir) |
| _CLIENT_DIR = os.path.join(_PARENT_DIR, "client") |
| _SERVER_DIR = os.path.join(_PARENT_DIR, "server") |
| _TEST_DIR = os.path.join(_PARENT_DIR, "test") |
| |
| sys.path.insert(1, _PARENT_DIR) |
| import chrome_paths |
| import util |
| sys.path.remove(_PARENT_DIR) |
| |
| sys.path.insert(1, _CLIENT_DIR) |
| import chromedriver |
| import webelement |
| sys.path.remove(_CLIENT_DIR) |
| |
| sys.path.insert(1, _SERVER_DIR) |
| import server |
| sys.path.remove(_SERVER_DIR) |
| |
| sys.path.insert(1, _TEST_DIR) |
| import unittest_util |
| import webserver |
| sys.path.remove(_TEST_DIR) |
| |
| sys.path.insert(0,os.path.join(chrome_paths.GetSrc(), 'third_party', |
| 'catapult', 'third_party', 'gsutil', |
| 'third_party', 'monotonic')) |
| from monotonic import monotonic |
| |
| _TEST_DATA_DIR = os.path.join(chrome_paths.GetTestData(), 'chromedriver') |
| |
| if util.IsLinux(): |
| sys.path.insert(0, os.path.join(chrome_paths.GetSrc(), 'third_party', |
| 'catapult', 'devil')) |
| from devil.android import device_utils |
| from devil.android import forwarder |
| |
| sys.path.insert(0, os.path.join(chrome_paths.GetSrc(), 'build', 'android')) |
| import devil_chromium |
| from pylib import constants |
| |
| |
| _NEGATIVE_FILTER = [ |
| # This test is too flaky on the bots, but seems to run perfectly fine |
| # on developer workstations. |
| 'ChromeDriverTest.testEmulateNetworkConditionsNameSpeed', |
| 'ChromeDriverTest.testEmulateNetworkConditionsSpeed', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=833 |
| 'ChromeDriverTest.testAlertOnNewWindow', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532 |
| 'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout', |
| # testFocus is failing |
| 'JavaScriptTests.testFocus', |
| ] |
| |
| |
| _OS_SPECIFIC_FILTER = {} |
| _OS_SPECIFIC_FILTER['win'] = [ |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=299 |
| 'ChromeLogPathCapabilityTest.testChromeLogPath', |
| # https://bugs.chromium.org/p/chromium/issues/detail?id=1011095 |
| 'ChromeDownloadDirTest.testFileDownloadAfterTabHeadless', |
| 'ChromeDownloadDirTest.testFileDownloadWithClickHeadless', |
| 'ChromeDownloadDirTest.testFileDownloadWithGetHeadless', |
| ] |
| _OS_SPECIFIC_FILTER['linux'] = [ |
| ] |
| _OS_SPECIFIC_FILTER['mac'] = [ |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1927 |
| # https://crbug.com/1036636 |
| 'MobileEmulationCapabilityTest.testTapElement', |
| # https://bugs.chromium.org/p/chromium/issues/detail?id=1011225 |
| 'ChromeDriverTest.testActionsMultiTouchPoint', |
| ] |
| |
| _DESKTOP_NEGATIVE_FILTER = [ |
| # Desktop doesn't support touch (without --touch-events). |
| 'ChromeDriverTestLegacy.testTouchSingleTapElement', |
| 'ChromeDriverTest.testTouchDownMoveUpElement', |
| 'ChromeDriverTestLegacy.testTouchScrollElement', |
| 'ChromeDriverTestLegacy.testTouchDoubleTapElement', |
| 'ChromeDriverTestLegacy.testTouchLongPressElement', |
| 'ChromeDriverTest.testTouchFlickElement', |
| 'ChromeDriverAndroidTest.*', |
| ] |
| |
| _INTEGRATION_NEGATIVE_FILTER = [ |
| # The following test is flaky on Windows and Mac. |
| 'ChromeDownloadDirTest.testDownloadDirectoryOverridesExistingPreferences', |
| # ChromeDriverLogTest tests an internal ChromeDriver feature, not needed |
| # for integration test. |
| 'ChromeDriverLogTest.*', |
| # ChromeDriverPageLoadTimeoutTest is flaky, particularly on Mac. |
| 'ChromeDriverPageLoadTimeoutTest.*', |
| # Some trivial test cases that provide no additional value beyond what are |
| # already tested by other test cases. |
| 'ChromeDriverTest.testGetCurrentWindowHandle', |
| 'ChromeDriverTest.testStartStop', |
| # https://crbug.com/867511 |
| 'ChromeDriverTest.testWindowMaximize', |
| # LaunchApp is an obsolete API. |
| 'ChromeExtensionsCapabilityTest.testCanLaunchApp', |
| # PerfTest takes a long time, requires extra setup, and adds little value |
| # to integration testing. |
| 'PerfTest.*', |
| # HeadlessInvalidCertificateTest is sometimes flaky. |
| 'HeadlessInvalidCertificateTest.*', |
| # Similar issues with HeadlessChromeDriverTest. |
| 'HeadlessChromeDriverTest.*', |
| # Flaky: https://crbug.com/899919 |
| 'SessionHandlingTest.testGetSessions', |
| # Flaky due to occasional timeout in starting Chrome |
| 'ZChromeStartRetryCountTest.testChromeStartRetryCount', |
| ] |
| |
| |
| def _GetDesktopNegativeFilter(): |
| filter = _NEGATIVE_FILTER + _DESKTOP_NEGATIVE_FILTER |
| os = util.GetPlatformName() |
| if os in _OS_SPECIFIC_FILTER: |
| filter += _OS_SPECIFIC_FILTER[os] |
| return filter |
| |
| _ANDROID_NEGATIVE_FILTER = {} |
| _ANDROID_NEGATIVE_FILTER['chrome'] = ( |
| _NEGATIVE_FILTER + [ |
| # Android doesn't support switches and extensions. |
| 'ChromeSwitchesCapabilityTest.*', |
| 'ChromeExtensionsCapabilityTest.*', |
| 'MobileEmulationCapabilityTest.*', |
| 'ChromeDownloadDirTest.*', |
| # https://crbug.com/274650 |
| 'ChromeDriverTest.testCloseWindow', |
| # Most window operations don't make sense on Android. |
| 'ChromeDriverTest.testWindowFullScreen', |
| 'ChromeDriverTest.testWindowPosition', |
| 'ChromeDriverTest.testWindowSize', |
| 'ChromeDriverTest.testWindowRect', |
| 'ChromeDriverTest.testWindowMaximize', |
| 'ChromeDriverTest.testWindowMinimize', |
| 'ChromeLogPathCapabilityTest.testChromeLogPath', |
| # Connecting to running browser is not supported on Android. |
| 'RemoteBrowserTest.*', |
| # Don't enable perf testing on Android yet. |
| 'PerfTest.*', |
| # Android doesn't support multiple sessions on one device. |
| 'SessionHandlingTest.testGetSessions', |
| # Android doesn't use the chrome://print dialog. |
| 'ChromeDriverTest.testCanSwitchToPrintPreviewDialog', |
| # Chrome 44+ for Android doesn't dispatch the dblclick event |
| 'ChromeDriverTest.testMouseDoubleClick', |
| # Page cannot be loaded from file:// URI in Android unless it |
| # is stored in device. |
| 'ChromeDriverTest.testCanClickAlertInIframes', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2081 |
| 'ChromeDriverTest.testCloseWindowUsingJavascript', |
| # Android doesn't support headless mode |
| 'HeadlessInvalidCertificateTest.*', |
| 'HeadlessChromeDriverTest.*', |
| # Tests of the desktop Chrome launch process. |
| 'LaunchDesktopTest.*', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2737 |
| 'ChromeDriverTest.testTakeElementScreenshot', |
| 'ChromeDriverTest.testTakeElementScreenshotInIframe', |
| # setWindowBounds not supported on Android |
| 'ChromeDriverTest.testTakeLargeElementScreenshot', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2786 |
| 'ChromeDriverTest.testActionsTouchTap', |
| 'ChromeDriverTest.testTouchDownMoveUpElement', |
| 'ChromeDriverTest.testTouchFlickElement', |
| # Android has no concept of tab or window, and will always lose focus |
| # on tab creation. https://crbug.com/chromedriver/3018 |
| 'ChromeDriverTest.testNewWindowDoesNotFocus', |
| 'ChromeDriverTest.testNewTabDoesNotFocus', |
| # Android does not support the virtual authenticator environment. |
| 'ChromeDriverSecureContextTest.*', |
| # Covered by Desktop tests; can't create 2 browsers in Android |
| 'SupportIPv4AndIPv6.testSupportIPv4AndIPv6', |
| # Browser context management is not supported by Android |
| 'ChromeDriverTest.testClipboardPermissions', |
| 'ChromeDriverTest.testMidiPermissions', |
| 'ChromeDriverTest.testMultiplePermissions', |
| 'ChromeDriverTest.testNewWindowSameDomainHasSamePermissions', |
| 'ChromeDriverTest.testPermissionStates', |
| 'ChromeDriverTest.testPermissionsOpaqueOriginsThrowError', |
| 'ChromeDriverTest.testPermissionsSameOrigin', |
| 'ChromeDriverTest.testPermissionsSameOriginDoesNotAffectOthers', |
| 'ChromeDriverTest.testPersistentStoragePermissions', |
| 'ChromeDriverTest.testPushAndNotificationsPermissions', |
| 'ChromeDriverTest.testSensorPermissions', |
| 'ChromeDriverTest.testSettingPermissionDoesNotAffectOthers', |
| # Android does not allow changing window size |
| 'JavaScriptTests.*', |
| ] |
| ) |
| _ANDROID_NEGATIVE_FILTER['chrome_stable'] = ( |
| _ANDROID_NEGATIVE_FILTER['chrome'] + [ |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2350 |
| 'ChromeDriverTest.testSlowIFrame', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2503 |
| 'ChromeDriverTest.testGetLogOnClosedWindow', |
| 'ChromeDriverTest.testGetWindowHandles', |
| 'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly', |
| 'ChromeDriverTest.testSwitchToWindow', |
| # Feature not yet supported in this version |
| 'ChromeDriverTest.testGenerateTestReport', |
| ] |
| ) |
| _ANDROID_NEGATIVE_FILTER['chrome_beta'] = ( |
| _ANDROID_NEGATIVE_FILTER['chrome'] + [ |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2503 |
| 'ChromeDriverTest.testGetLogOnClosedWindow', |
| 'ChromeDriverTest.testGetWindowHandles', |
| 'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly', |
| 'ChromeDriverTest.testSwitchToWindow', |
| # Feature not yet supported in this version |
| 'ChromeDriverTest.testGenerateTestReport', |
| ] |
| ) |
| _ANDROID_NEGATIVE_FILTER['chromium'] = ( |
| _ANDROID_NEGATIVE_FILTER['chrome'] + [] |
| ) |
| _ANDROID_NEGATIVE_FILTER['chromedriver_webview_shell'] = ( |
| _ANDROID_NEGATIVE_FILTER['chrome_stable'] + [ |
| # WebView doesn't support emulating network conditions. |
| 'ChromeDriverTest.testEmulateNetworkConditions', |
| 'ChromeDriverTest.testEmulateNetworkConditionsNameSpeed', |
| 'ChromeDriverTest.testEmulateNetworkConditionsOffline', |
| 'ChromeDriverTest.testEmulateNetworkConditionsSpeed', |
| 'ChromeDriverTest.testEmulateNetworkConditionsName', |
| # WebView shell doesn't support popups or popup blocking. |
| 'ChromeDriverTest.testPopups', |
| 'ChromeDriverTest.testDontGoBackOrGoForward', |
| # ChromeDriver WebView shell doesn't support multiple tabs. |
| 'ChromeDriverTest.testCloseWindowUsingJavascript', |
| 'ChromeDriverTest.testGetWindowHandles', |
| 'ChromeDriverTest.testSwitchToWindow', |
| 'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly', |
| 'ChromeDriverTest.testGetLogOnClosedWindow', |
| # The WebView shell that we test against (on KitKat) does not perform |
| # cross-process navigations. |
| # TODO(samuong): reenable when it does. |
| 'ChromeDriverPageLoadTimeoutTest.testPageLoadTimeoutCrossDomain', |
| 'ChromeDriverPageLoadTimeoutTest.' |
| 'testHistoryNavigationWithPageLoadTimeout', |
| # Webview shell doesn't support Alerts. |
| 'ChromeDriverTest.testAlert', |
| 'ChromeDriverTest.testAlertOnNewWindow', |
| 'ChromeDesiredCapabilityTest.testUnexpectedAlertBehaviour', |
| 'ChromeDriverTest.testAlertHandlingOnPageUnload', |
| 'ChromeDriverTest.testClickElementAfterNavigation', |
| 'ChromeDriverTest.testGetLogOnWindowWithAlert', |
| 'ChromeDriverTest.testSendTextToAlert', |
| 'ChromeDriverTest.testUnexpectedAlertOpenExceptionMessage', |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2332 |
| 'ChromeDriverTestLegacy.testTouchScrollElement', |
| ] |
| ) |
| |
| |
| 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, download_dir=None, **kwargs): |
| if server_url is None: |
| server_url = _CHROMEDRIVER_SERVER_URL |
| |
| if (not _ANDROID_PACKAGE_KEY and 'debugger_address' not in kwargs and |
| '_MINIDUMP_PATH' in globals()): |
| # Environment required for minidump not supported on Android |
| # minidumpPath will fail parsing if debugger_address is set |
| if 'experimental_options' in kwargs: |
| if 'minidumpPath' not in kwargs['experimental_options']: |
| kwargs['experimental_options']['minidumpPath'] = _MINIDUMP_PATH |
| else: |
| kwargs['experimental_options'] = {'minidumpPath': _MINIDUMP_PATH} |
| |
| android_package = None |
| android_activity = None |
| android_process = None |
| if _ANDROID_PACKAGE_KEY: |
| android_package = constants.PACKAGE_INFO[_ANDROID_PACKAGE_KEY].package |
| if _ANDROID_PACKAGE_KEY == 'chromedriver_webview_shell': |
| android_activity = constants.PACKAGE_INFO[_ANDROID_PACKAGE_KEY].activity |
| android_process = '%s:main' % android_package |
| |
| driver = chromedriver.ChromeDriver(server_url, |
| chrome_binary=_CHROME_BINARY, |
| android_package=android_package, |
| android_activity=android_activity, |
| android_process=android_process, |
| download_dir=download_dir, |
| test_name=self.id(), |
| **kwargs) |
| self._drivers += [driver] |
| return driver |
| |
| def WaitForNewWindow(self, driver, old_handles, check_closed_windows=True): |
| """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. |
| check_closed_windows: If True, assert that no windows are closed before |
| the new window is added. |
| |
| Returns: |
| Handle to a new window. None if timeout. |
| """ |
| deadline = monotonic() + 20 |
| while monotonic() < deadline: |
| handles = driver.GetWindowHandles() |
| if check_closed_windows: |
| self.assertTrue(set(old_handles).issubset(handles)) |
| new_handles = set(handles).difference(set(old_handles)) |
| if len(new_handles) > 0: |
| return new_handles.pop() |
| time.sleep(0.01) |
| return None |
| |
| def WaitForCondition(self, predicate, timeout=5, timestep=0.1): |
| """Wait for a condition to become true. |
| |
| Args: |
| predicate: A function that returns a boolean value. |
| """ |
| deadline = monotonic() + timeout |
| while monotonic() < deadline: |
| if predicate(): |
| return True |
| time.sleep(timestep) |
| return False |
| |
| |
| class ChromeDriverBaseTestWithWebServer(ChromeDriverBaseTest): |
| |
| @staticmethod |
| def GlobalSetUp(): |
| ChromeDriverBaseTestWithWebServer._http_server = webserver.WebServer( |
| chrome_paths.GetTestData()) |
| ChromeDriverBaseTestWithWebServer._sync_server = webserver.SyncWebServer() |
| cert_path = os.path.join(chrome_paths.GetTestData(), |
| 'chromedriver/invalid_ssl_cert.pem') |
| ChromeDriverBaseTestWithWebServer._https_server = webserver.WebServer( |
| chrome_paths.GetTestData(), cert_path) |
| |
| def respondWithUserAgentString(request): |
| return {}, """ |
| <html> |
| <body>%s</body> |
| </html>""" % request.GetHeader('User-Agent') |
| |
| def respondWithUserAgentStringUseDeviceWidth(request): |
| return {}, """ |
| <html> |
| <head> |
| <meta name="viewport" content="width=device-width,minimum-scale=1.0"> |
| </head> |
| <body>%s</body> |
| </html>""" % request.GetHeader('User-Agent') |
| |
| ChromeDriverBaseTestWithWebServer._http_server.SetCallbackForPath( |
| '/userAgent', respondWithUserAgentString) |
| ChromeDriverBaseTestWithWebServer._http_server.SetCallbackForPath( |
| '/userAgentUseDeviceWidth', respondWithUserAgentStringUseDeviceWidth) |
| |
| if _ANDROID_PACKAGE_KEY: |
| ChromeDriverBaseTestWithWebServer._device = ( |
| device_utils.DeviceUtils.HealthyDevices()[0]) |
| http_host_port = ( |
| ChromeDriverBaseTestWithWebServer._http_server._server.server_port) |
| sync_host_port = ( |
| ChromeDriverBaseTestWithWebServer._sync_server._server.server_port) |
| https_host_port = ( |
| ChromeDriverBaseTestWithWebServer._https_server._server.server_port) |
| forwarder.Forwarder.Map( |
| [(http_host_port, http_host_port), (sync_host_port, sync_host_port), |
| (https_host_port, https_host_port)], |
| ChromeDriverBaseTestWithWebServer._device) |
| |
| @staticmethod |
| def GlobalTearDown(): |
| if _ANDROID_PACKAGE_KEY: |
| forwarder.Forwarder.UnmapAllDevicePorts(ChromeDriverTest._device) |
| ChromeDriverBaseTestWithWebServer._http_server.Shutdown() |
| ChromeDriverBaseTestWithWebServer._https_server.Shutdown() |
| |
| @staticmethod |
| def GetHttpUrlForFile(file_path): |
| return ChromeDriverBaseTestWithWebServer._http_server.GetUrl() + file_path |
| |
| |
| class ChromeDriverTestWithCustomCapability(ChromeDriverBaseTestWithWebServer): |
| |
| def testEagerMode(self): |
| send_response = threading.Event() |
| def waitAndRespond(): |
| send_response.wait(10) |
| self._sync_server.RespondWithContent('#') |
| thread = threading.Thread(target=waitAndRespond) |
| |
| self._http_server.SetDataForPath('/top.html', |
| """ |
| <html><body> |
| <div id='top'> |
| <img src='%s'> |
| </div> |
| </body></html>""" % self._sync_server.GetUrl()) |
| eager_driver = self.CreateDriver(page_load_strategy='eager') |
| thread.start() |
| start_eager = monotonic() |
| eager_driver.Load(self._http_server.GetUrl() + '/top.html') |
| stop_eager = monotonic() |
| send_response.set() |
| eager_time = stop_eager - start_eager |
| self.assertTrue(eager_time < 9) |
| thread.join() |
| |
| def testDoesntWaitWhenPageLoadStrategyIsNone(self): |
| class HandleRequest(object): |
| def __init__(self): |
| self.sent_hello = threading.Event() |
| |
| def slowPage(self, request): |
| self.sent_hello.wait(2) |
| return {}, """ |
| <html> |
| <body>hello</body> |
| </html>""" |
| |
| handler = HandleRequest() |
| self._http_server.SetCallbackForPath('/slow', handler.slowPage) |
| |
| driver = self.CreateDriver(page_load_strategy='none') |
| self.assertEquals('none', driver.capabilities['pageLoadStrategy']) |
| |
| driver.Load(self._http_server.GetUrl() + '/chromedriver/empty.html') |
| start = monotonic() |
| driver.Load(self._http_server.GetUrl() + '/slow') |
| self.assertTrue(monotonic() - start < 2) |
| handler.sent_hello.set() |
| self.WaitForCondition(lambda: 'hello' in driver.GetPageSource()) |
| self.assertTrue('hello' in driver.GetPageSource()) |
| |
| def testUnsupportedPageLoadStrategyRaisesException(self): |
| self.assertRaises(chromedriver.InvalidArgument, |
| self.CreateDriver, page_load_strategy="unsupported") |
| |
| |
| class ChromeDriverTest(ChromeDriverBaseTestWithWebServer): |
| """End to end tests for ChromeDriver.""" |
| |
| 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() |
| |
| # crbug.com/p/chromedriver/issues/detail?id=2995 exposed that some libraries |
| # introduce circular function references. Functions should not be serialized |
| # or treated as an object - this test checks that circular function |
| # definitions are allowed (despite how they are not spec-compliant. |
| def testExecuteScriptWithSameFunctionReference(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript("""function copyMe() { return 1; } |
| Function.prototype.foo = copyMe; |
| const obj = {}; |
| obj['buzz'] = copyMe; |
| return obj;""") |
| |
| def _newWindowDoesNotFocus(self, window_type='window'): |
| current_handles = self._driver.GetWindowHandles() |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/focus_blur_test.html')) |
| new_window = self._driver.NewWindow(window_type=window_type) |
| text = self._driver.FindElement('css selector', '#result').GetText() |
| |
| self.assertTrue(new_window['handle'] not in current_handles) |
| self.assertTrue(new_window['handle'] in self._driver.GetWindowHandles()) |
| self.assertEquals(text, 'PASS') |
| |
| def testNewWindowDoesNotFocus(self): |
| self._newWindowDoesNotFocus(window_type='window') |
| |
| def testNewTabDoesNotFocus(self): |
| self._newWindowDoesNotFocus(window_type='tab') |
| |
| def testCloseWindow(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('css selector', '#link').Click() |
| new_window_handle = self.WaitForNewWindow(self._driver, 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, 'css selector', '#link') |
| close_returned_handles = self._driver.CloseWindow() |
| self.assertRaises(chromedriver.NoSuchWindow, |
| self._driver.GetCurrentWindowHandle) |
| new_handles = self._driver.GetWindowHandles() |
| self.assertEquals(close_returned_handles, new_handles) |
| 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()) |
| close_handles = self._driver.CloseWindow() |
| # CloseWindow quits the session if on the last window. |
| if handle is not new_handles[-1]: |
| from_get_window_handles = self._driver.GetWindowHandles() |
| self.assertEquals(close_handles, from_get_window_handles) |
| |
| def testCloseWindowUsingJavascript(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('css selector', '#link').Click() |
| new_window_handle = self.WaitForNewWindow(self._driver, 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, 'css selector', '#link') |
| self._driver.ExecuteScript('window.close()') |
| with self.assertRaises(chromedriver.NoSuchWindow): |
| self._driver.GetTitle() |
| |
| def testGetWindowHandles(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('css selector', '#link').Click() |
| self.assertNotEqual(None, self.WaitForNewWindow(self._driver, old_handles)) |
| |
| def testGetWindowHandlesInPresenceOfSharedWorker(self): |
| self._driver.Load( |
| self.GetHttpUrlForFile('/chromedriver/shared_worker.html')) |
| old_handles = self._driver.GetWindowHandles() |
| |
| 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('css selector', '#link').Click() |
| new_window_handle = self.WaitForNewWindow(self._driver, 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, 'css selector', '#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): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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.SetTimeouts({'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 testExecuteScriptTimeout(self): |
| self._driver.SetTimeouts({'script': 0}) |
| self.assertRaises( |
| chromedriver.ScriptTimeout, |
| self._driver.ExecuteScript, |
| 'return 2') |
| |
| # Regular script can still run afterwards. |
| self._driver.SetTimeouts({'script': 1000}) |
| self.assertEquals( |
| 4, |
| self._driver.ExecuteScript('return 4')) |
| |
| 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 testSwitchToParentFrame(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/nested.html')) |
| self.assertTrue('One' in self._driver.GetPageSource()) |
| self._driver.SwitchToFrameByIndex(0) |
| self.assertTrue('Two' in self._driver.GetPageSource()) |
| self._driver.SwitchToFrameByIndex(0) |
| self.assertTrue('Three' in self._driver.GetPageSource()) |
| self._driver.SwitchToParentFrame() |
| self.assertTrue('Two' in self._driver.GetPageSource()) |
| self._driver.SwitchToParentFrame() |
| self.assertTrue('One' in self._driver.GetPageSource()) |
| |
| def testSwitchToNestedFrame(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/nested_frameset.html')) |
| self._driver.SwitchToFrameByIndex(0) |
| self._driver.FindElement("css selector", "#link") |
| self._driver.SwitchToMainFrame() |
| self._driver.SwitchToFrame('2Frame') |
| self._driver.FindElement("css selector", "#l1") |
| self._driver.SwitchToMainFrame() |
| self._driver.SwitchToFrame('fourth_frame') |
| self.assertTrue('One' in self._driver.GetPageSource()) |
| self._driver.SwitchToMainFrame() |
| self._driver.SwitchToFrameByIndex(4) |
| self._driver.FindElement("css selector", "#aa1") |
| |
| 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 testSwitchToStaleFrame(self): |
| self._driver.ExecuteScript( |
| 'var frame = document.createElement("iframe");' |
| 'frame.id="id";' |
| 'frame.name="name";' |
| 'document.body.appendChild(frame);') |
| element = self._driver.FindElement("css selector", "#id") |
| self._driver.SwitchToFrame(element) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| with self.assertRaises(chromedriver.StaleElementReference): |
| self._driver.SwitchToFrame(element) |
| |
| 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.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>a</div><div>b</div>";') |
| self.assertTrue( |
| isinstance(self._driver.FindElement('tag name', 'div'), |
| webelement.WebElement)) |
| |
| def testNoSuchElementExceptionMessage(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>a</div><div>b</div>";') |
| self.assertRaisesRegexp(chromedriver.NoSuchElement, |
| 'no such element: Unable ' |
| 'to locate element: {"method":"tag name",' |
| '"selector":"divine"}', |
| self._driver.FindElement, |
| 'tag name', 'divine') |
| |
| def testFindElements(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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.WebElement)) |
| |
| def testFindChildElement(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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.WebElement)) |
| |
| def testFindChildElements(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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.WebElement)) |
| |
| def testClickElement(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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 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 testClickElementAfterNavigation(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/link_nav.html')) |
| link = self._driver.FindElement('css selector', '#l1') |
| link.Click() |
| alert_button = self._driver.FindElement('css selector', '#aa1') |
| alert_button.Click() |
| self.assertTrue(self._driver.IsAlertOpen()) |
| |
| def testActionsMouseMove(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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;') |
| actions = ({"actions": [{ |
| "actions": [{"duration": 32, "type": "pause"}], |
| "id": "0", |
| "type": "none" |
| }, { |
| "type":"pointer", |
| "actions":[{"type": "pointerMove", "x": 10, "y": 10}], |
| "parameters": {"pointerType": "mouse"}, |
| "id": "pointer1"}]}) |
| self._driver.PerformActions(actions) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testActionsMouseClick(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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;') |
| actions = ({"actions": [{ |
| "type":"pointer", |
| "actions":[{"type": "pointerMove", "x": 10, "y": 10}, |
| {"type": "pointerDown", "button": 0}, |
| {"type": "pointerUp", "button": 0}], |
| "parameters": {"pointerType": "mouse"}, |
| "id": "pointer1"}]}) |
| self._driver.PerformActions(actions) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testActionsMouseDoubleClick(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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;') |
| actions = ({"actions": [{ |
| "type":"pointer", |
| "actions":[{"type": "pointerMove", "x": 10, "y": 10}, |
| {"type": "pointerDown", "button": 0}, |
| {"type": "pointerUp", "button": 0}, |
| {"type": "pointerDown", "button": 0}, |
| {"type": "pointerUp", "button": 0}], |
| "parameters": {"pointerType": "mouse"}, |
| "id": "pointer1"}]}) |
| self._driver.PerformActions(actions) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testActionsMouseDrag(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/drag.html')) |
| target = self._driver.FindElement('css selector', '#target') |
| |
| # Move to center of target element and drag it to a new location. |
| actions = ({'actions': [{ |
| "actions": [{"duration": 32, "type": "pause"}, |
| {"duration": 32, "type": "pause"}, |
| {"duration": 32, "type": "pause"}], |
| "id": "0", |
| "type": "none" |
| }, { |
| 'type': 'pointer', |
| 'actions': [ |
| {'type': 'pointerMove', 'x': 100, 'y': 100}, |
| {'type': 'pointerDown', 'button': 0}, |
| {'type': 'pointerMove', 'x': 200, 'y': 250} |
| ], |
| 'parameters': {'pointerType': 'mouse'}, |
| 'id': 'pointer1'}]}) |
| time.sleep(1) |
| self._driver.PerformActions(actions) |
| time.sleep(1) |
| rect = target.GetRect() |
| self.assertAlmostEqual(150, rect['x'], delta=1) |
| self.assertAlmostEqual(200, rect['y'], delta=1) |
| |
| # Without releasing mouse button, should continue the drag. |
| actions = ({'actions': [{ |
| "actions": [{"duration": 32, "type": "pause"}], |
| "id": "0", |
| "type": "none" |
| }, { |
| 'type': 'pointer', |
| 'actions': [ |
| {'type': 'pointerMove', 'x': 30, 'y': 40, 'origin': 'pointer'} |
| ], |
| 'parameters': {'pointerType': 'mouse'}, |
| 'id': 'pointer1'}]}) |
| time.sleep(1) |
| self._driver.PerformActions(actions) |
| time.sleep(1) |
| rect = target.GetRect() |
| self.assertAlmostEqual(180, rect['x'], delta=1) |
| self.assertAlmostEqual(240, rect['y'], delta=1) |
| |
| # Releasing mouse button stops the drag. |
| actions = ({'actions': [{ |
| "actions": [{"duration": 32, "type": "pause"}, |
| {"duration": 32, "type": "pause"}], |
| "id": "0", |
| "type": "none" |
| }, { |
| 'type': 'pointer', |
| 'actions': [ |
| {'type': 'pointerUp', 'button': 0}, |
| {'type': 'pointerMove', 'x': 50, 'y': 50, 'origin': 'pointer'} |
| ], |
| 'parameters': {'pointerType': 'mouse'}, |
| 'id': 'pointer1'}]}) |
| time.sleep(1) |
| self._driver.PerformActions(actions) |
| time.sleep(1) |
| rect = target.GetRect() |
| self.assertAlmostEqual(180, rect['x'], delta=1) |
| self.assertAlmostEqual(240, rect['y'], delta=1) |
| |
| def testActionsTouchTap(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| 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;') |
| actions = ({"actions": [{ |
| "type":"pointer", |
| "actions":[{"type": "pointerMove", "x": 10, "y": 10}, |
| {"type": "pointerDown"}, |
| {"type": "pointerUp"}], |
| "parameters": {"pointerType": "touch"}, |
| "id": "pointer1"}]}) |
| self._driver.PerformActions(actions) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testActionsMultiTouchPoint(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript( |
| ''' |
| document.body.innerHTML |
| = "<div id='div' autofocus style='width:200px; height:200px'>"; |
| window.events = []; |
| const div = document.getElementById('div'); |
| div.addEventListener('touchstart', event => { |
| window.events.push( |
| {type: event.type, |
| x: event.touches[event.touches.length - 1].clientX, |
| y: event.touches[event.touches.length - 1].clientY}); |
| }); |
| div.addEventListener('touchend', event => { |
| window.events.push( |
| {type: event.type}); |
| }); |
| ''') |
| time.sleep(1) |
| |
| actions = ({"actions": [{ |
| "type":"pointer", |
| "actions":[{"type": "pointerMove", "x": 50, "y": 50}, |
| {"type": "pointerDown"}, |
| {"type": "pointerUp"}], |
| "parameters": {"pointerType": "touch"}, |
| "id": "pointer1"}, |
| { |
| "type":"pointer", |
| "actions":[{"type": "pointerMove", "x": 60, "y": 60}, |
| {"type": "pointerDown"}, |
| {"type": "pointerUp"}], |
| "parameters": {"pointerType": "touch"}, |
| "id": "pointer2"}]}) |
| self._driver.PerformActions(actions) |
| time.sleep(1) |
| events = self._driver.ExecuteScript('return window.events') |
| self.assertEquals(4, len(events)) |
| self.assertEquals("touchstart", events[0]['type']) |
| self.assertEquals("touchstart", events[1]['type']) |
| self.assertEquals("touchend", events[2]['type']) |
| self.assertEquals("touchend", events[3]['type']) |
| self.assertAlmostEqual(50, events[0]['x'], delta=1) |
| self.assertAlmostEqual(50, events[0]['y'], delta=1) |
| self.assertAlmostEqual(60, events[1]['x'], delta=1) |
| self.assertAlmostEqual(60, events[1]['y'], delta=1) |
| |
| self._driver.ReleaseActions() |
| |
| def testActionsMulti(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript( |
| ''' |
| document.body.innerHTML |
| = "<div id='div' autofocus style='width:200px; height:200px'>"; |
| window.events = []; |
| const div = document.getElementById('div'); |
| div.addEventListener('click', event => { |
| window.events.push( |
| {x: event.clientX, y: event.clientY}); |
| }); |
| ''') |
| |
| # Move mouse to (50, 50). |
| self._driver.PerformActions({'actions': [ |
| { |
| 'type': 'pointer', |
| 'id': 'mouse', |
| 'actions': [ {'type': 'pointerMove', 'x': 50, 'y': 50} ] |
| } |
| ]}) |
| |
| # Click mouse button. ChromeDriver should remember that mouse is at |
| # (50, 50). |
| self._driver.PerformActions({'actions': [ |
| { |
| 'type': 'pointer', |
| 'id': 'mouse', |
| 'actions': [ |
| {'type': 'pointerDown', "button": 0}, |
| {'type': 'pointerUp', "button": 0} |
| ] |
| } |
| ]}) |
| events = self._driver.ExecuteScript('return window.events') |
| self.assertEquals(1, len(events)) |
| self.assertAlmostEqual(50, events[0]['x'], delta=1) |
| self.assertAlmostEqual(50, events[0]['y'], delta=1) |
| |
| # Clean up action states, move mouse back to (0, 0). |
| self._driver.ReleaseActions() |
| |
| # Move mouse relative by (80, 80) pixels, and then click. |
| self._driver.PerformActions({'actions': [ |
| { |
| 'type': 'pointer', |
| 'id': 'mouse', |
| 'actions': [ |
| {'type': 'pointerMove', 'x': 80, 'y': 80, 'origin': 'pointer'}, |
| {'type': 'pointerDown', "button": 0}, |
| {'type': 'pointerUp', "button": 0} |
| ] |
| } |
| ]}) |
| events = self._driver.ExecuteScript('return window.events') |
| self.assertEquals(2, len(events)) |
| self.assertAlmostEqual(80, events[1]['x'], delta=1) |
| self.assertAlmostEqual(80, events[1]['y'], delta=1) |
| |
| self._driver.ReleaseActions() |
| |
| def testActionsPause(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript( |
| ''' |
| document.body.innerHTML |
| = "<input type='text' autofocus style='width:100px; height:100px'>"; |
| window.events = []; |
| const input = document.getElementsByTagName("input")[0]; |
| const listener |
| = e => window.events.push({type: e.type, time: e.timeStamp}); |
| input.addEventListener("keydown", listener); |
| input.addEventListener("keyup", listener); |
| input.addEventListener("mousedown", listener); |
| ''') |
| |
| # Actions on 3 devices, across 6 ticks, with 200 ms pause at ticks 1 to 4. |
| # Tick "key" device "pointer" device "none" device |
| # 0 move |
| # 1 pause 200 ms pointer down pause 100 ms |
| # 2 "a" key down pointer up pause 200 ms |
| # 3 "a" key up pause 200 ms |
| # 4 "b" key down move 200 ms |
| # 5 "b" key up |
| actions = {'actions': [ |
| { |
| 'type': 'key', |
| 'id': 'key', |
| 'actions': [ |
| {'type': 'pause'}, |
| {'type': 'pause', 'duration': 200}, |
| {'type': 'keyDown', 'value': 'a'}, |
| {'type': 'keyUp', 'value': 'a'}, |
| {'type': 'keyDown', 'value': 'b'}, |
| {'type': 'keyUp', 'value': 'b'}, |
| ] |
| }, |
| { |
| 'type': 'pointer', |
| 'id': 'mouse', |
| 'actions': [ |
| {'type': 'pointerMove', 'x': 50, 'y': 50}, |
| {'type': 'pointerDown', 'button': 0}, |
| {'type': 'pointerUp', 'button': 0}, |
| {'type': 'pause', 'duration': 200}, |
| {'type': 'pointerMove', 'duration': 200, 'x': 10, 'y': 10}, |
| ] |
| }, |
| { |
| 'type': 'none', |
| 'id': 'none', |
| 'actions': [ |
| {'type': 'pause'}, |
| {'type': 'pause', 'duration': 100}, |
| {'type': 'pause', 'duration': 200}, |
| ] |
| } |
| ]} |
| |
| self._driver.PerformActions(actions) |
| events = self._driver.ExecuteScript('return window.events') |
| expected_events = ['mousedown', 'keydown', 'keyup', 'keydown', 'keyup'] |
| self.assertEquals(len(expected_events), len(events)) |
| for i in range(len(events)): |
| self.assertEqual(expected_events[i], events[i]['type']) |
| if i > 0: |
| elapsed_time = events[i]['time'] - events[i-1]['time'] |
| self.assertGreaterEqual(elapsed_time, 200) |
| |
| def testReleaseActions(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript( |
| ''' |
| document.body.innerHTML |
| = "<input id='target' type='text' style='width:200px; height:200px'>"; |
| window.events = []; |
| const recordKeyEvent = event => { |
| window.events.push( |
| {type: event.type, code: event.code}); |
| }; |
| const recordMouseEvent = event => { |
| window.events.push( |
| {type: event.type, x: event.clientX, y: event.clientY}); |
| }; |
| const target = document.getElementById('target'); |
| target.addEventListener('keydown', recordKeyEvent); |
| target.addEventListener('keyup', recordKeyEvent); |
| target.addEventListener('mousedown', recordMouseEvent); |
| target.addEventListener('mouseup', recordMouseEvent); |
| ''') |
| |
| # Move mouse to (50, 50), press a mouse button, and press a key. |
| self._driver.PerformActions({'actions': [ |
| { |
| 'type': 'pointer', |
| 'id': 'mouse', |
| 'actions': [ |
| {'type': 'pointerMove', 'x': 50, 'y': 50}, |
| {'type': 'pointerDown', "button": 0} |
| ] |
| }, |
| { |
| 'type': 'key', |
| 'id': 'key', |
| 'actions': [ |
| {'type': 'pause'}, |
| {'type': 'pause'}, |
| {'type': 'keyDown', 'value': 'a'} |
| ] |
| } |
| ]}) |
| |
| events = self._driver.ExecuteScript('return window.events') |
| self.assertEquals(2, len(events)) |
| self.assertEquals('mousedown', events[0]['type']) |
| self.assertAlmostEqual(50, events[0]['x'], delta=1) |
| self.assertAlmostEqual(50, events[0]['y'], delta=1) |
| self.assertEquals('keydown', events[1]['type']) |
| self.assertEquals('KeyA', events[1]['code']) |
| |
| self._driver.ReleaseActions() |
| |
| events = self._driver.ExecuteScript('return window.events') |
| self.assertEquals(4, len(events)) |
| self.assertEquals('keyup', events[2]['type']) |
| self.assertEquals('KeyA', events[2]['code']) |
| self.assertEquals('mouseup', events[3]['type']) |
| self.assertAlmostEqual(50, events[3]['x'], delta=1) |
| self.assertAlmostEqual(50, events[3]['y'], delta=1) |
| |
| def testPageLoadStrategyIsNormalByDefault(self): |
| self.assertEquals('normal', |
| self._driver.capabilities['pageLoadStrategy']) |
| |
| def testClearElement(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| text = self._driver.ExecuteScript( |
| 'document.body.innerHTML = \'<input type="text" value="abc">\';' |
| 'return document.getElementsByTagName("input")[0];') |
| value = self._driver.ExecuteScript('return arguments[0].value;', text) |
| self.assertEquals('abc', value) |
| text.Clear() |
| value = self._driver.ExecuteScript('return arguments[0].value;', text) |
| self.assertEquals('', value) |
| |
| def testSendKeysToInputFileElement(self): |
| file_name = os.path.join(_TEST_DATA_DIR, 'anchor_download_test.png') |
| self._driver.Load(ChromeDriverTest.GetHttpUrlForFile( |
| '/chromedriver/file_input.html')) |
| elem = self._driver.FindElement('css selector', '#id_file') |
| elem.SendKeys(file_name) |
| text = self._driver.ExecuteScript( |
| 'var input = document.getElementById("id_file").value;' |
| 'return input;') |
| self.assertEquals('C:\\fakepath\\anchor_download_test.png', text); |
| if not _ANDROID_PACKAGE_KEY: |
| self.assertRaises(chromedriver.InvalidArgument, |
| elem.SendKeys, "/blah/blah/blah") |
| |
| def testSendKeysToNonTypeableInputElement(self): |
| self._driver.Load("about:blank") |
| self._driver.ExecuteScript( |
| "document.body.innerHTML = '<input type=\"color\">';") |
| elem = self._driver.FindElement('tag name', 'input'); |
| input_value = '#7fffd4' |
| elem.SendKeys(input_value) |
| value = elem.GetProperty('value') |
| self.assertEquals(input_value, value) |
| |
| def testGetElementAttribute(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/attribute_colon_test.html')) |
| elem = self._driver.FindElement("css selector", "*[name='phones']") |
| self.assertEquals('3', elem.GetAttribute('size')) |
| |
| def testGetElementProperty(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/two_inputs.html')) |
| elem = self._driver.FindElement("css selector", "#first") |
| self.assertEquals('text', elem.GetProperty('type')) |
| self.assertEquals('first', elem.GetProperty('id')) |
| |
| def testGetElementSpecialCharAttribute(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/attribute_colon_test.html')) |
| elem = self._driver.FindElement("css selector", "*[name='phones']") |
| self.assertEquals('colonvalue', elem.GetAttribute('ext:qtip')) |
| |
| def testGetCurrentUrl(self): |
| url = self.GetHttpUrlForFile('/chromedriver/frame_test.html') |
| self._driver.Load(url) |
| self.assertEquals(url, self._driver.GetCurrentUrl()) |
| self._driver.SwitchToFrame(self._driver.FindElement('tag name', 'iframe')) |
| self.assertEquals(url, self._driver.GetCurrentUrl()) |
| |
| def testGoBackAndGoForward(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.GoBack() |
| self._driver.GoForward() |
| |
| def testDontGoBackOrGoForward(self): |
| # We need to run this test in a new tab so that it is isolated from previous |
| # test runs. |
| old_windows = self._driver.GetWindowHandles() |
| self._driver.ExecuteScript('window.open("about:blank")') |
| new_window = self.WaitForNewWindow(self._driver, old_windows) |
| self._driver.SwitchToWindow(new_window) |
| self.assertEquals('about:blank', self._driver.GetCurrentUrl()) |
| self._driver.GoBack() |
| self.assertEquals('about:blank', self._driver.GetCurrentUrl()) |
| self._driver.GoForward() |
| self.assertEquals('about:blank', self._driver.GetCurrentUrl()) |
| |
| def testBackNavigationAfterClickElement(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/link_nav.html')) |
| link = self._driver.FindElement('css selector', '#l1') |
| link.Click() |
| self._driver.GoBack() |
| self.assertNotEqual('data:,', self._driver.GetCurrentUrl()) |
| self.assertEquals(self.GetHttpUrlForFile('/chromedriver/link_nav.html'), |
| self._driver.GetCurrentUrl()) |
| |
| def testAlertHandlingOnPageUnload(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript('window.onbeforeunload=function(){return true}') |
| self._driver.FindElement('tag name', 'body').Click() |
| self._driver.GoBack() |
| self.assertTrue(self._driver.IsAlertOpen()) |
| self._driver.HandleAlert(True) |
| self.assertFalse(self._driver.IsAlertOpen()) |
| |
| def testRefresh(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.Refresh() |
| |
| def testAlert(self): |
| self.assertFalse(self._driver.IsAlertOpen()) |
| self._driver.ExecuteScript('window.confirmed = confirm(\'HI\');') |
| 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 testSendTextToAlert(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript('prompt = window.prompt()') |
| self.assertTrue(self._driver.IsAlertOpen()) |
| self._driver.HandleAlert(True, 'TextToPrompt') |
| self.assertEquals('TextToPrompt', |
| self._driver.ExecuteScript('return prompt')) |
| self._driver.ExecuteScript('window.confirmed = confirm(\'HI\');') |
| self.assertRaises(chromedriver.ElementNotInteractable, |
| self._driver.HandleAlert, |
| True, 'textToConfirm') |
| self._driver.HandleAlert(True) #for closing the previous alert. |
| self._driver.ExecuteScript('window.onbeforeunload=function(){return true}') |
| self._driver.FindElement('tag name', 'body').Click() |
| self._driver.Refresh() |
| self.assertTrue(self._driver.IsAlertOpen()) |
| self.assertRaises(chromedriver.UnsupportedOperation, |
| self._driver.HandleAlert, |
| True, 'textToOnBeforeUnload') |
| |
| def testAlertOnNewWindow(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| old_windows = self._driver.GetWindowHandles() |
| self._driver.ExecuteScript("window.open('%s')" % |
| self.GetHttpUrlForFile('/chromedriver/alert_onload.html')) |
| new_window = self.WaitForNewWindow(self._driver, old_windows) |
| self.assertNotEqual(None, new_window) |
| self._driver.SwitchToWindow(new_window) |
| self.assertTrue(self._driver.IsAlertOpen()) |
| self._driver.HandleAlert(False) |
| self.assertFalse(self._driver.IsAlertOpen()) |
| |
| 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('tag name', 'a').Click() |
| new_window = self.WaitForNewWindow(self._driver, 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(self._driver, 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('tag name', 'body')) |
| |
| def testWindowPosition(self): |
| rect = self._driver.GetWindowRect() |
| self._driver.SetWindowRect(None, None, rect[2], rect[3]) |
| self.assertEquals(rect, self._driver.GetWindowRect()) |
| |
| # Resize so the window isn't moved offscreen. |
| # See https://bugs.chromium.org/p/chromedriver/issues/detail?id=297. |
| self._driver.SetWindowRect(640, 400, None, None) |
| |
| self._driver.SetWindowRect(None, None, 100, 200) |
| self.assertEquals([640, 400, 100, 200], self._driver.GetWindowRect()) |
| |
| def testWindowSize(self): |
| rect = self._driver.GetWindowRect() |
| self._driver.SetWindowRect(rect[0], rect[1], None, None) |
| self.assertEquals(rect, self._driver.GetWindowRect()) |
| |
| self._driver.SetWindowRect(640, 400, None, None) |
| self.assertEquals([640, 400, rect[2], rect[3]], |
| self._driver.GetWindowRect()) |
| |
| def testWindowRect(self): |
| old_window_rect = self._driver.GetWindowRect() |
| self._driver.SetWindowRect(*old_window_rect) |
| self.assertEquals(self._driver.GetWindowRect(), old_window_rect) |
| |
| target_window_rect = [640, 400, 100, 200] |
| target_window_rect_dict = {'width': 640, 'height': 400, 'x': 100, 'y': 200} |
| returned_window_rect = self._driver.SetWindowRect(*target_window_rect) |
| self.assertEquals(self._driver.GetWindowRect(), target_window_rect) |
| self.assertEquals(returned_window_rect, target_window_rect_dict) |
| |
| def testWindowMaximize(self): |
| old_rect_list = [640, 400, 100, 200] |
| self._driver.SetWindowRect(*old_rect_list) |
| new_rect = self._driver.MaximizeWindow() |
| new_rect_list = [ |
| new_rect['width'], |
| new_rect['height'], |
| new_rect['x'], |
| new_rect['y'] |
| ] |
| self.assertNotEqual(old_rect_list, new_rect_list) |
| |
| self._driver.SetWindowRect(*old_rect_list) |
| self.assertEquals(old_rect_list, self._driver.GetWindowRect()) |
| |
| def testWindowMinimize(self): |
| handle_prefix = "CDwindow-" |
| handle = self._driver.GetCurrentWindowHandle() |
| target = handle[len(handle_prefix):] |
| self._driver.SetWindowRect(640, 400, 100, 200) |
| rect = self._driver.MinimizeWindow() |
| expected_rect = {u'y': 200, u'width': 640, u'height': 400, u'x': 100} |
| |
| #check it returned the correct rect |
| for key in expected_rect.keys(): |
| self.assertEquals(expected_rect[key], rect[key]) |
| |
| # check its minimized |
| res = self._driver.SendCommandAndGetResult('Browser.getWindowForTarget', |
| {'targetId': target}) |
| self.assertEquals('minimized', res['bounds']['windowState']) |
| |
| def testWindowFullScreen(self): |
| old_rect_list = [640, 400, 100, 200] |
| self._driver.SetWindowRect(*old_rect_list) |
| self.assertEquals(self._driver.GetWindowRect(), old_rect_list) |
| new_rect = self._driver.FullScreenWindow() |
| new_rect_list = [ |
| new_rect['width'], |
| new_rect['height'], |
| new_rect['x'], |
| new_rect['y'] |
| ] |
| self.assertNotEqual(old_rect_list, new_rect_list) |
| |
| self._driver.SetWindowRect(*old_rect_list) |
| self.assertEquals(old_rect_list, self._driver.GetWindowRect()) |
| |
| def testConsoleLogSources(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/console_log.html')) |
| logs = self._driver.GetLog('browser') |
| |
| self.assertEqual('javascript', logs[0]['source']) |
| self.assertTrue('TypeError' in logs[0]['message']) |
| |
| self.assertEqual('network', logs[1]['source']) |
| self.assertTrue('nonexistent.png' in logs[1]['message']) |
| self.assertTrue('404' in logs[1]['message']) |
| |
| # Sometimes, we also get an error for a missing favicon. |
| if len(logs) > 2: |
| self.assertEqual('network', logs[2]['source']) |
| self.assertTrue('favicon.ico' in logs[2]['message']) |
| self.assertTrue('404' in logs[2]['message']) |
| self.assertEqual(3, len(logs)) |
| else: |
| self.assertEqual(2, len(logs)) |
| |
| def testPendingConsoleLog(self): |
| new_logs = [""] |
| def GetPendingLogs(driver): |
| response = driver.GetLog('browser') |
| new_logs[0] = [x for x in response if x['source'] == 'console-api'] |
| return new_logs[0] |
| |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/pending_console_log.html')) |
| logs = self._driver.GetLog('browser') |
| self.assertEqual('console-api', logs[0]['source']) |
| self.assertTrue('"InitialError" 2018 "Third"' in logs[0]['message']) |
| |
| self.WaitForCondition(lambda: len(GetPendingLogs(self._driver)) > 0 , 6) |
| self.assertEqual('console-api', new_logs[0][0]['source']) |
| self.assertTrue('"RepeatedError" "Second" "Third"' in |
| new_logs[0][0]['message']) |
| |
| def testGetLogOnClosedWindow(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| old_handles = self._driver.GetWindowHandles() |
| self._driver.FindElement('css selector', '#link').Click() |
| self.WaitForNewWindow(self._driver, old_handles) |
| self._driver.CloseWindow() |
| try: |
| self._driver.GetLog('browser') |
| except chromedriver.ChromeDriverException as e: |
| self.fail('exception while calling GetLog on a closed tab: ' + e.message) |
| |
| def testGetLogOnWindowWithAlert(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.ExecuteScript('alert("alert!");') |
| try: |
| self._driver.GetLog('browser') |
| except Exception as e: |
| self.fail(e.message) |
| |
| def testDoesntHangOnDebugger(self): |
| self._driver.Load('about:blank') |
| self._driver.ExecuteScript('debugger;') |
| |
| def testChromeDriverSendLargeData(self): |
| script = 'return "0".repeat(10e6);' |
| lots_of_data = self._driver.ExecuteScript(script) |
| self.assertEquals('0'.zfill(int(10e6)), lots_of_data) |
| |
| def testEmulateNetworkConditions(self): |
| # Network conditions must be set before it can be retrieved. |
| self.assertRaises(chromedriver.UnknownError, |
| self._driver.GetNetworkConditions) |
| |
| # DSL: 2Mbps throughput, 5ms RTT |
| latency = 5 |
| throughput = 2048 * 1024 |
| self._driver.SetNetworkConditions(latency, throughput, throughput) |
| |
| network = self._driver.GetNetworkConditions() |
| self.assertEquals(latency, network['latency']); |
| self.assertEquals(throughput, network['download_throughput']); |
| self.assertEquals(throughput, network['upload_throughput']); |
| self.assertEquals(False, network['offline']); |
| |
| # Network Conditions again cannot be retrieved after they've been deleted. |
| self._driver.DeleteNetworkConditions() |
| self.assertRaises(chromedriver.UnknownError, |
| self._driver.GetNetworkConditions) |
| |
| def testEmulateNetworkConditionsName(self): |
| # DSL: 2Mbps throughput, 5ms RTT |
| # latency = 5 |
| # throughput = 2048 * 1024 |
| self._driver.SetNetworkConditionsName('DSL') |
| |
| network = self._driver.GetNetworkConditions() |
| self.assertEquals(5, network['latency']); |
| self.assertEquals(2048*1024, network['download_throughput']); |
| self.assertEquals(2048*1024, network['upload_throughput']); |
| self.assertEquals(False, network['offline']); |
| |
| def testEmulateNetworkConditionsSpeed(self): |
| # Warm up the browser. |
| self._http_server.SetDataForPath( |
| '/', "<html><body>blank</body></html>") |
| self._driver.Load(self._http_server.GetUrl() + '/') |
| |
| # DSL: 2Mbps throughput, 5ms RTT |
| latency = 5 |
| throughput_kbps = 2048 |
| throughput = throughput_kbps * 1024 |
| self._driver.SetNetworkConditions(latency, throughput, throughput) |
| |
| _32_bytes = " 0 1 2 3 4 5 6 7 8 9 A B C D E F" |
| _1_megabyte = _32_bytes * 32768 |
| self._http_server.SetDataForPath( |
| '/1MB', |
| "<html><body>%s</body></html>" % _1_megabyte) |
| start = monotonic() |
| self._driver.Load(self._http_server.GetUrl() + '/1MB') |
| finish = monotonic() |
| duration = finish - start |
| actual_throughput_kbps = 1024 / duration |
| self.assertLessEqual(actual_throughput_kbps, throughput_kbps * 1.5) |
| self.assertGreaterEqual(actual_throughput_kbps, throughput_kbps / 1.5) |
| |
| def testEmulateNetworkConditionsNameSpeed(self): |
| # Warm up the browser. |
| self._http_server.SetDataForPath( |
| '/', "<html><body>blank</body></html>") |
| self._driver.Load(self._http_server.GetUrl() + '/') |
| |
| # DSL: 2Mbps throughput, 5ms RTT |
| throughput_kbps = 2048 |
| throughput = throughput_kbps * 1024 |
| self._driver.SetNetworkConditionsName('DSL') |
| |
| _32_bytes = " 0 1 2 3 4 5 6 7 8 9 A B C D E F" |
| _1_megabyte = _32_bytes * 32768 |
| self._http_server.SetDataForPath( |
| '/1MB', |
| "<html><body>%s</body></html>" % _1_megabyte) |
| start = monotonic() |
| self._driver.Load(self._http_server.GetUrl() + '/1MB') |
| finish = monotonic() |
| duration = finish - start |
| actual_throughput_kbps = 1024 / duration |
| self.assertLessEqual(actual_throughput_kbps, throughput_kbps * 1.5) |
| self.assertGreaterEqual(actual_throughput_kbps, throughput_kbps / 1.5) |
| |
| def testEmulateNetworkConditionsOffline(self): |
| # A workaround for crbug.com/177511; when setting offline, the throughputs |
| # must be 0. |
| self._driver.SetNetworkConditions(0, 0, 0, offline=True) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| # The "X is not available" title is set after the page load event fires, so |
| # we have to explicitly wait for this to change. We can't rely on the |
| # navigation tracker to block the call to Load() above. |
| self.WaitForCondition(lambda: 'is not available' in self._driver.GetTitle()) |
| |
| def testSendCommandAndGetResult(self): |
| """Sends a custom command to the DevTools debugger and gets the result""" |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html')) |
| params = {} |
| document = self._driver.SendCommandAndGetResult('DOM.getDocument', params) |
| self.assertTrue('root' in document) |
| |
| def _FindElementInShadowDom(self, css_selectors): |
| """Find an element inside shadow DOM using CSS selectors. |
| The last item in css_selectors identify the element to find. All preceding |
| selectors identify the hierarchy of shadow hosts to traverse in order to |
| reach the target shadow DOM.""" |
| current = None |
| for selector in css_selectors: |
| if current is None: |
| # First CSS selector, start from root DOM. |
| current = self._driver |
| else: |
| # current is a shadow host selected previously. |
| # Enter the corresponding shadow root. |
| current = self._driver.ExecuteScript( |
| 'return arguments[0].shadowRoot', current) |
| current = current.FindElement('css selector', selector) |
| return current |
| |
| def testShadowDomFindElement(self): |
| """Checks that chromedriver can find elements in a shadow DOM.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| self.assertTrue(self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#textBox"])) |
| |
| def testShadowDomFindChildElement(self): |
| """Checks that chromedriver can find child elements from a shadow DOM |
| element.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| elem = self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#childDiv"]) |
| self.assertTrue(elem.FindElement("css selector", "#textBox")) |
| |
| def testShadowDomFindElementFailsFromRoot(self): |
| """Checks that chromedriver can't find elements in a shadow DOM from |
| root.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| # can't find element from the root without /deep/ |
| with self.assertRaises(chromedriver.NoSuchElement): |
| self._driver.FindElement("css selector", "#textBox") |
| |
| def testShadowDomText(self): |
| """Checks that chromedriver can find extract the text from a shadow DOM |
| element.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| elem = self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#heading"]) |
| self.assertEqual("Child", elem.GetText()) |
| |
| def testShadowDomSendKeys(self): |
| """Checks that chromedriver can call SendKeys on a shadow DOM element.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| elem = self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#textBox"]) |
| elem.SendKeys("bar") |
| self.assertEqual("foobar", self._driver.ExecuteScript( |
| 'return arguments[0].value;', elem)) |
| |
| def testShadowDomClear(self): |
| """Checks that chromedriver can call Clear on a shadow DOM element.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| elem = self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#textBox"]) |
| elem.Clear() |
| self.assertEqual("", self._driver.ExecuteScript( |
| 'return arguments[0].value;', elem)) |
| |
| def testShadowDomClick(self): |
| """Checks that chromedriver can call Click on an element in a shadow DOM.""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| # Wait for page to stabilize. See https://crbug.com/954553#c7 |
| time.sleep(1) |
| elem = self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#button"]) |
| elem.Click() |
| # the button's onClicked handler changes the text box's value |
| self.assertEqual("Button Was Clicked", self._driver.ExecuteScript( |
| 'return arguments[0].value;', |
| self._FindElementInShadowDom(["#innerDiv", "#parentDiv", "#textBox"]))) |
| |
| def testShadowDomActionClick(self): |
| '''Checks that ChromeDriver can use actions API to click on an element in a |
| shadow DOM.''' |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| # Wait for page to stabilize. See https://crbug.com/954553#c7 |
| time.sleep(1) |
| elem = self._FindElementInShadowDom( |
| ['#innerDiv', '#parentDiv', '#button']) |
| actions = ({'actions': [{ |
| 'type': 'pointer', |
| 'actions': [{'type': 'pointerMove', 'x': 0, 'y': 0, 'origin': elem}, |
| {'type': 'pointerDown', 'button': 0}, |
| {'type': 'pointerUp', 'button': 0}], |
| 'id': 'pointer1'}]}) |
| self._driver.PerformActions(actions) |
| # the button's onClicked handler changes the text box's value |
| self.assertEqual('Button Was Clicked', self._driver.ExecuteScript( |
| 'return arguments[0].value;', |
| self._FindElementInShadowDom(['#innerDiv', '#parentDiv', '#textBox']))) |
| |
| def testShadowDomStaleReference(self): |
| """Checks that trying to manipulate shadow DOM elements that are detached |
| from the document raises a StaleElementReference exception""" |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/shadow_dom_test.html')) |
| elem = self._FindElementInShadowDom( |
| ["#innerDiv", "#parentDiv", "#button"]) |
| self._driver.ExecuteScript( |
| 'document.querySelector("#outerDiv").innerHTML="<div/>";') |
| with self.assertRaises(chromedriver.StaleElementReference): |
| elem.Click() |
| |
| def testTouchDownMoveUpElement(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/touch_action_tests.html')) |
| target = self._driver.FindElement('css selector', '#target') |
| location = target.GetLocation() |
| self._driver.TouchDown(location['x'], location['y']) |
| events = self._driver.FindElement('css selector', '#events') |
| self.assertEquals('events: touchstart', events.GetText()) |
| self._driver.TouchMove(location['x'] + 1, location['y'] + 1) |
| self.assertEquals('events: touchstart touchmove', events.GetText()) |
| self._driver.TouchUp(location['x'] + 1, location['y'] + 1) |
| self.assertEquals('events: touchstart touchmove touchend', events.GetText()) |
| |
| def testGetElementRect(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/absolute_position_element.html')) |
| target = self._driver.FindElement('css selector', '#target') |
| rect = target.GetRect() |
| self.assertEquals(18, rect['x']) |
| self.assertEquals(10, rect['y']) |
| self.assertEquals(200, rect['height']) |
| self.assertEquals(210, rect['width']) |
| |
| def testTouchFlickElement(self): |
| dx = 3 |
| dy = 4 |
| speed = 5 |
| flickTouchEventsPerSecond = 30 |
| moveEvents = int( |
| math.sqrt(dx * dx + dy * dy) * flickTouchEventsPerSecond / speed) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| div = self._driver.ExecuteScript( |
| 'document.body.innerHTML = "<div>old</div>";' |
| 'var div = document.getElementsByTagName("div")[0];' |
| 'div.addEventListener("touchstart", function() {' |
| ' div.innerHTML = "preMove0";' |
| '});' |
| 'div.addEventListener("touchmove", function() {' |
| ' res = div.innerHTML.match(/preMove(\d+)/);' |
| ' if (res != null) {' |
| ' div.innerHTML = "preMove" + (parseInt(res[1], 10) + 1);' |
| ' }' |
| '});' |
| 'div.addEventListener("touchend", function() {' |
| ' if (div.innerHTML == "preMove' + str(moveEvents) + '") {' |
| ' div.innerHTML = "new<br>";' |
| ' }' |
| '});' |
| 'return div;') |
| self._driver.TouchFlick(div, dx, dy, speed) |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'br'))) |
| |
| def testSwitchesToTopFrameAfterNavigation(self): |
| self._driver.Load('about:blank') |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/outer.html')) |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/outer.html')) |
| p = self._driver.FindElement('tag name', 'p') |
| self.assertEquals('Two', p.GetText()) |
| |
| def testSwitchesToTopFrameAfterRefresh(self): |
| self._driver.Load('about:blank') |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/outer.html')) |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame) |
| self._driver.Refresh() |
| p = self._driver.FindElement('tag name', 'p') |
| self.assertEquals('Two', p.GetText()) |
| |
| def testSwitchesToTopFrameAfterGoingBack(self): |
| self._driver.Load('about:blank') |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/outer.html')) |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/inner.html')) |
| self._driver.GoBack() |
| p = self._driver.FindElement('tag name', 'p') |
| self.assertEquals('Two', p.GetText()) |
| |
| def testCanSwitchToPrintPreviewDialog(self): |
| old_handles = self._driver.GetWindowHandles() |
| print >> sys.stdout, "Test debug: actual len of old_handles: " \ |
| + str(len(old_handles)) |
| self.assertEquals(1, len(old_handles)) |
| self._driver.ExecuteScript('setTimeout(function(){window.print();}, 0);') |
| new_window_handle = self.WaitForNewWindow(self._driver, old_handles) |
| if new_window_handle is None: |
| print >> sys.stdout, "Test debug: new_window_handle is None" |
| else: |
| print >> sys.stdout, "Test debug: new_window_handle is not None" |
| self.assertNotEqual(None, new_window_handle) |
| self._driver.SwitchToWindow(new_window_handle) |
| print >> sys.stdout, "Test debug: actual GetCurrentUrl: " \ |
| + self._driver.GetCurrentUrl() |
| self.assertEquals('chrome://print/', self._driver.GetCurrentUrl()) |
| |
| def testCanClickInIframes(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/nested.html')) |
| a = self._driver.FindElement('tag name', 'a') |
| a.Click() |
| frame_url = self._driver.ExecuteScript('return window.location.href') |
| self.assertTrue(frame_url.endswith('#one')) |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame) |
| a = self._driver.FindElement('tag name', 'a') |
| a.Click() |
| frame_url = self._driver.ExecuteScript('return window.location.href') |
| self.assertTrue(frame_url.endswith('#two')) |
| |
| def testDoesntHangOnFragmentNavigation(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html#x')) |
| |
| def SetCookie(self, request): |
| return {'Set-Cookie': 'x=y; HttpOnly'}, "<!DOCTYPE html><html></html>" |
| |
| def testGetHttpOnlyCookie(self): |
| self._http_server.SetCallbackForPath('/setCookie', self.SetCookie) |
| self._driver.Load(self.GetHttpUrlForFile('/setCookie')) |
| self._driver.AddCookie({'name': 'a', 'value': 'b'}) |
| cookies = self._driver.GetCookies() |
| self.assertEquals(2, len(cookies)) |
| for cookie in cookies: |
| self.assertIn('name', cookie) |
| if cookie['name'] == 'a': |
| self.assertFalse(cookie['httpOnly']) |
| elif cookie['name'] == 'x': |
| self.assertTrue(cookie['httpOnly']) |
| else: |
| self.fail('unexpected cookie: %s' % json.dumps(cookie)) |
| |
| def testCookiePath(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/long_url/empty.html')) |
| self._driver.AddCookie({'name': 'a', 'value': 'b'}) |
| self._driver.AddCookie({ |
| 'name': 'x', 'value': 'y', 'path': '/chromedriver/long_url'}) |
| cookies = self._driver.GetCookies() |
| self.assertEquals(2, len(cookies)) |
| for cookie in cookies: |
| self.assertIn('path', cookie) |
| if cookie['name'] == 'a': |
| self.assertEquals('/' , cookie['path']) |
| if cookie['name'] == 'x': |
| self.assertEquals('/chromedriver/long_url' , cookie['path']) |
| |
| def testGetNamedCookie(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/empty.html')) |
| self._driver.AddCookie({'name': 'a', 'value': 'b'}) |
| named_cookie = self._driver.GetNamedCookie('a') |
| self.assertEquals('a' , named_cookie['name']) |
| self.assertEquals('b' , named_cookie['value']) |
| self.assertRaisesRegexp( |
| chromedriver.NoSuchCookie, "no such cookie", |
| self._driver.GetNamedCookie, 'foo') |
| |
| def testDeleteCookie(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/empty.html')) |
| self._driver.AddCookie({'name': 'a', 'value': 'b'}) |
| self._driver.AddCookie({'name': 'x', 'value': 'y'}) |
| self._driver.AddCookie({'name': 'p', 'value': 'q'}) |
| cookies = self._driver.GetCookies() |
| self.assertEquals(3, len(cookies)) |
| self._driver.DeleteCookie('a') |
| self.assertEquals(2, len(self._driver.GetCookies())) |
| self._driver.DeleteAllCookies() |
| self.assertEquals(0, len(self._driver.GetCookies())) |
| |
| def testCookieForFrame(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/cross_domain_iframe.html')) |
| self._driver.AddCookie({'name': 'outer', 'value': 'main context'}) |
| |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame) |
| self.assertTrue(self.WaitForCondition( |
| lambda: 'outer.html' in |
| self._driver.ExecuteScript('return window.location.href'))) |
| self._driver.AddCookie({'name': 'inner', 'value': 'frame context'}) |
| cookies = self._driver.GetCookies() |
| self.assertEquals(1, len(cookies)) |
| self.assertEquals('inner', cookies[0]['name']) |
| |
| self._driver.SwitchToMainFrame() |
| cookies = self._driver.GetCookies() |
| self.assertEquals(1, len(cookies)) |
| self.assertEquals('outer', cookies[0]['name']) |
| |
| def testGetUrlOnInvalidUrl(self): |
| # Make sure we don't return 'chrome-error://chromewebdata/' (see |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1272). RFC 6761 |
| # requires domain registrars to keep 'invalid.' unregistered (see |
| # https://tools.ietf.org/html/rfc6761#section-6.4). |
| self._driver.Load('http://invalid./') |
| self.assertEquals('http://invalid./', self._driver.GetCurrentUrl()) |
| |
| def testCanClickAlertInIframes(self): |
| # This test requires that the page be loaded from a file:// URI, rather than |
| # the test HTTP server. |
| path = os.path.join(chrome_paths.GetTestData(), 'chromedriver', |
| 'page_with_frame.html') |
| url = 'file://' + urllib.pathname2url(path) |
| self._driver.Load(url) |
| frame = self._driver.FindElement('css selector', '#frm') |
| self._driver.SwitchToFrame(frame) |
| a = self._driver.FindElement('css selector', '#btn') |
| a.Click() |
| self.WaitForCondition(lambda: self._driver.IsAlertOpen()) |
| self._driver.HandleAlert(True) |
| |
| def testThrowErrorWithExecuteScript(self): |
| self.assertRaisesRegexp( |
| chromedriver.JavaScriptError, "some error", |
| self._driver.ExecuteScript, 'throw new Error("some error")') |
| |
| def testDoesntCrashWhenScriptLogsUndefinedValue(self): |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1547 |
| self._driver.ExecuteScript('var b; console.log(b);') |
| |
| def testDoesntThrowWhenPageLogsUndefinedValue(self): |
| # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1547 |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/log_undefined_value.html')) |
| |
| def testCanSetCheckboxWithSpaceKey(self): |
| self._driver.Load('about:blank') |
| self._driver.ExecuteScript( |
| "document.body.innerHTML = '<input type=\"checkbox\">';") |
| checkbox = self._driver.FindElement('tag name', 'input') |
| self.assertFalse( |
| self._driver.ExecuteScript('return arguments[0].checked', checkbox)) |
| checkbox.SendKeys(' ') |
| self.assertTrue( |
| self._driver.ExecuteScript('return arguments[0].checked', checkbox)) |
| |
| def testElementReference(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/element_ref.html')) |
| element = self._driver.FindElement('css selector', '#link') |
| self._driver.FindElements('tag name', 'br') |
| w3c_id_length = 36 |
| if (self._driver.w3c_compliant): |
| self.assertEquals(len(element._id), w3c_id_length) |
| |
| def testFindElementWhenElementIsOverridden(self): |
| self._driver.Load('about:blank') |
| self._driver.ExecuteScript( |
| 'document.body.appendChild(document.createElement("a"));') |
| self._driver.ExecuteScript('window.Element = {}') |
| self.assertEquals(1, len(self._driver.FindElements('tag name', 'a'))) |
| |
| def testExecuteScriptWhenObjectPrototypeIsModified(self): |
| # Some JavaScript libraries (e.g. MooTools) do things like this. For context |
| # see https://bugs.chromium.org/p/chromedriver/issues/detail?id=1521 |
| self._driver.Load('about:blank') |
| self._driver.ExecuteScript('Object.prototype.$family = undefined;') |
| self.assertEquals(1, self._driver.ExecuteScript('return 1;')) |
| |
| def testWebWorkerFrames(self): |
| """Verify web worker frames are handled correctly. |
| |
| Regression test for bug |
| https://bugs.chromium.org/p/chromedriver/issues/detail?id=2340. |
| The bug was triggered by opening a page with web worker, and then opening a |
| page on a different site. We simulate a different site by using 'localhost' |
| as the host name (default is '127.0.0.1'). |
| """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/web_worker.html')) |
| self._driver.Load(self._http_server.GetUrl('localhost') |
| + '/chromedriver/empty.html') |
| |
| def testWaitForCurrentFrameToLoad(self): |
| """Verify ChromeDriver waits for loading events of current frame |
| Regression test for bug |
| https://bugs.chromium.org/p/chromedriver/issues/detail?id=3164 |
| Clicking element in frame triggers reload of that frame, click should not |
| return until loading is complete. |
| """ |
| def waitAndRespond(): |
| # test may not detect regression without small sleep. |
| # locally, .2 didn't fail before code change, .3 did |
| time.sleep(.5) |
| self._sync_server.RespondWithContent( |
| """ |
| <html> |
| <body> |
| <p id='valueToRead'>11</p> |
| </body> |
| </html> |
| """) |
| |
| self._http_server.SetDataForPath('/page10.html', |
| """ |
| <html> |
| <head> |
| <title> |
| Frame |
| </title> |
| <script> |
| function reloadWith(i) { |
| window.location.assign('%s'); |
| } |
| </script> |
| </head> |
| <body> |
| <button id='prev' onclick="reloadWith(9)">-1</button> |
| <button id='next' onclick="reloadWith(11)">+1</button> |
| <p id='valueToRead'>10</p> |
| </body> |
| </html> |
| """ % self._sync_server.GetUrl()) |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/page_for_next_iframe.html')) |
| frame = self._driver.FindElement('tag name', 'iframe') |
| self._driver.SwitchToFrame(frame); |
| thread = threading.Thread(target=waitAndRespond) |
| thread.start() |
| self._driver.FindElement('css selector', '#next').Click() |
| value_display = self._driver.FindElement('css selector', '#valueToRead') |
| self.assertEquals('11', value_display.GetText()) |
| |
| def testSlowIFrame(self): |
| """Verify ChromeDriver does not wait for slow frames to load. |
| Regression test for bugs |
| https://bugs.chromium.org/p/chromedriver/issues/detail?id=2198 and |
| https://bugs.chromium.org/p/chromedriver/issues/detail?id=2350. |
| """ |
| def waitAndRespond(): |
| # Send iframe contents slowly |
| time.sleep(2) |
| self._sync_server.RespondWithContent( |
| '<html><div id=iframediv>IFrame contents</div></html>') |
| |
| self._http_server.SetDataForPath('/top.html', |
| """ |
| <html><body> |
| <div id='top'> |
| <input id='button' type="button" onclick="run()" value='Click'> |
| </div> |
| <script> |
| function run() { |
| var iframe = document.createElement('iframe'); |
| iframe.id = 'iframe'; |
| iframe.setAttribute('src', '%s'); |
| document.body.appendChild(iframe); |
| } |
| </script> |
| </body></html>""" % self._sync_server.GetUrl()) |
| self._driver.Load(self._http_server.GetUrl() + '/top.html') |
| thread = threading.Thread(target=waitAndRespond) |
| thread.start() |
| start = monotonic() |
| # Click should not wait for frame to load, so elapsed time from this |
| # command should be < 2 seconds. |
| self._driver.FindElement('css selector', '#button').Click() |
| self.assertLess(monotonic() - start, 2.0) |
| frame = self._driver.FindElement('css selector', '#iframe') |
| # WaitForPendingNavigations examines the load state of the current frame |
| # so ChromeDriver will wait for frame to load after SwitchToFrame |
| # start is reused because that began the pause for the frame load |
| self._driver.SwitchToFrame(frame) |
| self.assertGreaterEqual(monotonic() - start, 2.0) |
| self._driver.FindElement('css selector', '#iframediv') |
| thread.join() |
| |
| @staticmethod |
| def MakeRedImageTestScript(png_data_in_base64): |
| """Used by the takeElementScreenshot* tests to load the PNG image via a data |
| URI, analyze it, and PASS/FAIL depending on whether all the pixels are all |
| rgb(255,0,0).""" |
| return ( |
| """ |
| const resolve = arguments[arguments.length - 1]; |
| const image = new Image(); |
| image.onload = () => { |
| var canvas = document.createElement('canvas'); |
| canvas.width = image.width; |
| canvas.height = image.height; |
| var context = canvas.getContext('2d'); |
| context.drawImage(image, 0, 0); |
| const pixels = |
| context.getImageData(0, 0, image.width, image.height).data; |
| for (let i = 0; i < pixels.length; i += 4) { |
| if (pixels[i + 0] != 255 || // Red |
| pixels[i + 1] != 0 || // Green |
| pixels[i + 2] != 0) { // Blue |
| const message = ( |
| 'FAIL: Bad pixel rgb(' + pixels.slice(i, i + 3).join(',') + |
| ') at offset ' + i + ' from ' + image.src); |
| // "Disabled" on Mac 10.10: 1/15 test runs produces an incorrect |
| // pixel. Since no later Mac version, nor any other platform, |
| // exhibits this problem, we assume this is due to a bug in this |
| // specific version of Mac OS. So, just log the error and pass |
| // the test. http://crbug.com/913603 |
| if (navigator.userAgent.indexOf('Mac OS X 10_10') != -1) { |
| console.error(message); |
| console.error('Passing test due to Mac 10.10-specific bug.'); |
| resolve('PASS'); |
| } else { |
| resolve(message); |
| } |
| return; |
| } |
| } |
| resolve('PASS'); |
| }; |
| image.src = 'data:image/png;base64,%s'; |
| """ % png_data_in_base64.replace("'", "\\'")) |
| |
| def takeScreenshotAndVerifyCorrect(self, element): |
| """ Takes screenshot of given element and returns |
| 'PASS' if all pixels in screenshot are rgb(255, 0, 0) |
| and 'FAIL' otherwise |
| """ |
| elementScreenshotPNGBase64 = element.TakeElementScreenshot() |
| self.assertIsNotNone(elementScreenshotPNGBase64) |
| return self._driver.ExecuteAsyncScript( |
| ChromeDriverTest.MakeRedImageTestScript(elementScreenshotPNGBase64)) |
| |
| def testTakeElementScreenshot(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/page_with_redbox.html')) |
| analysisResult = 'FAIL' |
| redElement = self._driver.FindElement('css selector', '#box') |
| analysisResult = self.takeScreenshotAndVerifyCorrect(redElement) |
| self.assertEquals('PASS', analysisResult) |
| |
| def testTakeElementScreenshotInIframe(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/page_with_iframe_redbox.html')) |
| frame = self._driver.FindElement('css selector', '#frm') |
| self._driver.SwitchToFrame(frame) |
| analysisResult = 'FAIL' |
| redElement = self._driver.FindElement('css selector', '#box') |
| analysisResult = self.takeScreenshotAndVerifyCorrect(redElement) |
| self.assertEquals('PASS', analysisResult) |
| |
| def testTakeLargeElementScreenshot(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/large_element.html')) |
| self._driver.SetWindowRect(500, 500, 0, 0) |
| # Wait for page to stabilize. See https://crbug.com/chromedriver/2986 |
| time.sleep(1) |
| redElement = self._driver.FindElement('css selector', '#A') |
| analysisResult = self.takeScreenshotAndVerifyCorrect(redElement) |
| self.assertEquals('PASS', analysisResult) |
| |
| def testGenerateTestReport(self): |
| self._driver.Load(self.GetHttpUrlForFile( |
| '/chromedriver/reporting_observer.html')) |
| self._driver.GenerateTestReport('test report message'); |
| report = self._driver.ExecuteScript('return window.result;') |
| |
| self.assertEquals('test', report['type']); |
| self.assertEquals('test report message', report['body']['message']); |
| |
| def GetPermissionWithQuery(self, query): |
| script = """ |
| let query = arguments[0]; |
| let done = arguments[1]; |
| console.log(done); |
| navigator.permissions.query(query) |
| .then(function(value) { |
| done({ status: 'success', value: value && value.state }); |
| }, function(error) { |
| done({ status: 'error', value: error && error.message }); |
| }); |
| """ |
| return self._driver.ExecuteAsyncScript(script, query) |
| |
| def GetPermission(self, name): |
| return self.GetPermissionWithQuery({ 'name': name }) |
| |
| def CheckPermission(self, response, expected_state): |
| self.assertEquals(response['status'], 'success') |
| self.assertEquals(response['value'], expected_state) |
| |
| def testPermissionsOpaqueOriginsThrowError(self): |
| """ Confirms that opaque origins cannot have overrides. """ |
| self._driver.Load("about:blank") |
| self.assertRaises(chromedriver.InvalidArgument, |
| self._driver.SetPermission, {'descriptor': { 'name': 'geolocation' }, |
| 'state': 'denied'}) |
| |
| def testPermissionStates(self): |
| """ Confirms that denied, granted, and prompt can be set. """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'geolocation' }, |
| 'state': 'denied' |
| }) |
| self.CheckPermission(self.GetPermission('geolocation'), 'denied') |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'geolocation' }, |
| 'state': 'granted' |
| }) |
| self.CheckPermission(self.GetPermission('geolocation'), 'granted') |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'geolocation' }, |
| 'state': 'prompt' |
| }) |
| self.CheckPermission(self.GetPermission('geolocation'), 'prompt') |
| |
| def testSettingPermissionDoesNotAffectOthers(self): |
| """ Confirm permissions do not affect unset permissions. """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| response = self.GetPermission('geolocation') |
| self.assertEquals(response['status'], 'success') |
| status = response['value'] |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'background-sync' }, |
| 'state': 'denied' |
| }) |
| self.CheckPermission(self.GetPermission('background-sync'), 'denied') |
| self.CheckPermission(self.GetPermission('geolocation'), status) |
| |
| def testMultiplePermissions(self): |
| """ Confirms multiple custom permissions can be set simultaneously. """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'geolocation' }, |
| 'state': 'denied' |
| }) |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'background-fetch' }, |
| 'state': 'prompt' |
| }) |
| self._driver.SetPermission({ |
| 'descriptor': { 'name': 'background-sync' }, |
| 'state': 'granted' |
| }) |
| self.CheckPermission(self.GetPermission('geolocation'), 'denied') |
| self.CheckPermission(self.GetPermission('background-fetch'), 'prompt') |
| self.CheckPermission(self.GetPermission('background-sync'), 'granted') |
| |
| def testSensorPermissions(self): |
| """ Tests sensor permissions. |
| |
| Currently, Chrome controls all sensor permissions (accelerometer, |
| magnetometer, gyroscope, ambient-light-sensor) with the 'sensors' |
| permission. This test demonstrates this internal implementation detail so |
| developers are aware of this behavior. |
| """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| parameters = { |
| 'descriptor': { 'name': 'magnetometer' }, |
| 'state': 'granted' |
| } |
| self._driver.SetPermission(parameters) |
| # Light sensor is not enabled by default, so it cannot be queried or set. |
| #self.CheckPermission(self.GetPermission('ambient-light-sensor'), 'granted') |
| self.CheckPermission(self.GetPermission('magnetometer'), 'granted') |
| self.CheckPermission(self.GetPermission('accelerometer'), 'granted') |
| self.CheckPermission(self.GetPermission('gyroscope'), 'granted') |
| parameters = { |
| 'descriptor': { 'name': 'gyroscope' }, |
| 'state': 'denied' |
| } |
| self._driver.SetPermission(parameters) |
| #self.CheckPermission(self.GetPermission('ambient-light-sensor'), 'denied') |
| self.CheckPermission(self.GetPermission('magnetometer'), 'denied') |
| self.CheckPermission(self.GetPermission('accelerometer'), 'denied') |
| self.CheckPermission(self.GetPermission('gyroscope'), 'denied') |
| |
| def testMidiPermissions(self): |
| """ Tests midi permission requirements. |
| |
| MIDI, sysex: true, when granted, should automatically grant regular MIDI |
| permissions. |
| When regular MIDI is denied, this should also imply MIDI with sysex is |
| denied. |
| """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| parameters = { |
| 'descriptor': { 'name': 'midi', 'sysex': True }, |
| 'state': 'granted' |
| } |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'granted') |
| parameters['descriptor']['sysex'] = False |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'granted') |
| |
| parameters = { |
| 'descriptor': { 'name': 'midi', 'sysex': False }, |
| 'state': 'denied' |
| } |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'denied') |
| # While this should be denied, Chrome does not do this. |
| # parameters['descriptor']['sysex'] = True should be denied. |
| |
| def testClipboardPermissions(self): |
| """ Tests clipboard permission requirements. |
| |
| clipboard-read with allowWithoutSanitization: true or false, and |
| clipboard-write with allowWithoutSanitization: true are bundled together |
| into one CLIPBOARD_READ_WRITE permission. |
| |
| clipboard write with allowWithoutSanitization: false is an auto-granted |
| permission. |
| """ |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| parameters = { |
| 'descriptor': { |
| 'name': 'clipboard-read' , |
| 'allowWithoutSanitization': False |
| }, |
| 'state': 'granted' |
| } |
| raw_write_parameters = { |
| 'descriptor': { |
| 'name': 'clipboard-write', |
| 'allowWithoutSanitization': True |
| } |
| } |
| |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'prompt') |
| self.CheckPermission(self.GetPermissionWithQuery( |
| raw_write_parameters['descriptor']), 'prompt') |
| |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'granted') |
| parameters['descriptor']['allowWithoutSanitization'] = True |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'granted') |
| parameters['descriptor']['name'] = 'clipboard-write' |
| self.CheckPermission(self.GetPermissionWithQuery(parameters['descriptor']), |
| 'granted') |
| |
| parameters = { |
| 'descriptor': { 'name': 'clipboard-write' }, |
| 'state': 'prompt' |
| } |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('clipboard-read'), 'granted') |
| self.CheckPermission(self.GetPermission('clipboard-write'), 'prompt') |
| |
| def testPersistentStoragePermissions(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| parameters = { |
| 'descriptor': { 'name': 'persistent-storage' }, |
| 'state': 'granted' |
| } |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('persistent-storage'), 'granted') |
| parameters['state'] = 'denied' |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('persistent-storage'), 'denied') |
| |
| def testPushAndNotificationsPermissions(self): |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| parameters = { |
| 'descriptor': { 'name': 'notifications' }, |
| 'state': 'granted' |
| } |
| push_descriptor = { |
| 'name': 'push', |
| 'userVisibleOnly': True |
| } |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('notifications'), 'granted') |
| self.CheckPermission(self.GetPermissionWithQuery(push_descriptor), |
| 'granted') |
| parameters['state'] = 'denied' |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('notifications'), 'denied') |
| self.CheckPermission(self.GetPermissionWithQuery(push_descriptor), 'denied') |
| push_descriptor['userVisibleOnly'] = False |
| parameters = { |
| 'descriptor': push_descriptor, |
| 'state': 'prompt' |
| } |
| self.assertRaises(chromedriver.InvalidArgument, |
| self._driver.SetPermission, parameters) |
| |
| def testPermissionsSameOrigin(self): |
| """ Assures permissions are shared between same-domain windows. """ |
| window_handle = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(window_handle) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/link_nav.html')) |
| another_window_handle = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(another_window_handle) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| |
| # Set permission. |
| parameters = { 'descriptor': { 'name': 'geolocation' }, 'state': 'granted' } |
| |
| # Test that they are present across the same domain. |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('geolocation'), 'granted') |
| self._driver.SwitchToWindow(window_handle) |
| self.CheckPermission(self.GetPermission('geolocation'), 'granted') |
| |
| def testNewWindowSameDomainHasSamePermissions(self): |
| """ Assures permissions are shared between same-domain windows, even when |
| window is created after permissions are set. """ |
| window_handle = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(window_handle) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| self._driver.SetPermission({ 'descriptor': { 'name': 'geolocation' }, |
| 'state': 'denied' }) |
| self.CheckPermission(self.GetPermission('geolocation'), 'denied') |
| same_domain = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(same_domain) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/link_nav.html')) |
| self.CheckPermission(self.GetPermission('geolocation'), 'denied') |
| |
| |
| def testPermissionsSameOriginDoesNotAffectOthers(self): |
| """ Tests whether permissions set between two domains affect others. """ |
| window_handle = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(window_handle) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/link_nav.html')) |
| another_window_handle = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(another_window_handle) |
| self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) |
| different_domain = self._driver.NewWindow()['handle'] |
| self._driver.SwitchToWindow(different_domain) |
| self._driver.Load('https://google.com') |
| self._driver.SetPermission({ 'descriptor': {'name': 'geolocation'}, |
| 'state': 'denied' }) |
| |
| # Switch for permissions. |
| self._driver.SwitchToWindow(another_window_handle) |
| |
| # Set permission. |
| parameters = { 'descriptor': { 'name': 'geolocation' }, 'state': 'prompt' } |
| |
| # Test that they are present across the same domain. |
| self._driver.SetPermission(parameters) |
| self.CheckPermission(self.GetPermission('geolocation'), 'prompt') |
| |
| self._driver.SwitchToWindow(window_handle) |
| self.CheckPermission(self.GetPermission('geolocation'), 'prompt') |
| |
| # Assert different domain is not the same. |
| self._driver.SwitchToWindow(different_domain) |
| self.CheckPermission(self.GetPermission('geolocation'), 'denied') |
| |
| # Tests that the webauthn:virtualAuthenticators capability is true on desktop |
| # and false on android. |
| def testWebauthnVirtualAuthenticatorsCapability(self): |
| is_desktop = _ANDROID_PACKAGE_KEY is None |
| self.assertEqual( |
| is_desktop, |
| self._driver.capabilities['webauthn:virtualAuthenticators']) |
| |
| # Tests that require a secure context. |
| class ChromeDriverSecureContextTest(ChromeDriverBaseTestWithWebServer): |
| # The example attestation private key from the U2F spec at |
| # https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-example |
| # PKCS.8 encoded without encryption, as a base64url string. |
| privateKey = ("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q" |
| "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU" |
| "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB") |
| |
| @staticmethod |
| def GetHttpsUrlForFile(file_path, host=None): |
| return ChromeDriverSecureContextTest._https_server.GetUrl( |
| host) + file_path |
| |
| # Encodes a string in URL-safe base64 with no padding. |
| @staticmethod |
| def URLSafeBase64Encode(string): |
| encoded = base64.urlsafe_b64encode(string) |
| while encoded[-1] == "=": |
| encoded = encoded[0:-1] |
| return encoded |
| |
| # Decodes a base64 string with no padding. |
| @staticmethod |
| def UrlSafeBase64Decode(string): |
| string = string.encode("utf-8") |
| if len(string) % 4 != 0: |
| string += "=" * (4 - len(string) % 4) |
| return base64.urlsafe_b64decode(string) |
| |
| def setUp(self): |
| self._driver = self.CreateDriver( |
| accept_insecure_certs=True, |
| chrome_switches=['host-resolver-rules=MAP * 127.0.0.1']) |
| |
| def testAddVirtualAuthenticator(self): |
| script = """ |
| let done = arguments[0]; |
| registerCredential().then(done); |
| """ |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| hasResidentKey = False, |
| hasUserVerification = False, |
| isUserConsenting = True, |
| isUserVerified = True, |
| ) |
| result = self._driver.ExecuteAsyncScript(script) |
| self.assertEquals('OK', result['status']) |
| self.assertEquals(['usb'], result['credential']['transports']) |
| |
| def testAddVirtualAuthenticatorDefaultParams(self): |
| script = """ |
| let done = arguments[0]; |
| registerCredential().then(done); |
| """ |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap1/u2f', |
| transport = 'usb', |
| ) |
| result = self._driver.ExecuteAsyncScript(script) |
| self.assertEquals('OK', result['status']) |
| self.assertEquals(['usb'], result['credential']['transports']) |
| |
| def testRemoveVirtualAuthenticator(self): |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| |
| # Removing a non existent virtual authenticator should fail. |
| self.assertRaisesRegexp( |
| chromedriver.InvalidArgument, |
| 'Could not find a Virtual Authenticator matching the ID', |
| self._driver.RemoveVirtualAuthenticator, 'id') |
| |
| # Create an authenticator and try removing it. |
| authenticatorId = self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| hasResidentKey = False, |
| hasUserVerification = False, |
| ) |
| self._driver.RemoveVirtualAuthenticator(authenticatorId) |
| |
| # Trying to remove the same authenticator should fail. |
| self.assertRaisesRegexp( |
| chromedriver.InvalidArgument, |
| 'Could not find a Virtual Authenticator matching the ID', |
| self._driver.RemoveVirtualAuthenticator, authenticatorId) |
| |
| def testAddCredential(self): |
| |
| script = """ |
| let done = arguments[0]; |
| getCredential({ |
| type: "public-key", |
| id: new TextEncoder().encode("cred-1"), |
| transports: ["usb"], |
| }).then(done); |
| """ |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| |
| authenticatorId = self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| hasResidentKey = False, |
| hasUserVerification = False, |
| ) |
| |
| # Register a credential and try authenticating with it. |
| self._driver.AddCredential( |
| authenticatorId = authenticatorId, |
| credentialId = self.URLSafeBase64Encode("cred-1"), |
| isResidentCredential=False, |
| rpId="chromedriver.test", |
| privateKey=self.privateKey, |
| signCount=1, |
| ) |
| |
| result = self._driver.ExecuteAsyncScript(script) |
| self.assertEquals('OK', result['status']) |
| |
| def testAddCredentialBase64Errors(self): |
| # Test that AddCredential checks UrlBase64 parameteres. |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| |
| authenticatorId = self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| hasResidentKey = False, |
| hasUserVerification = False, |
| ) |
| |
| # Try adding a credentialId that is encoded in vanilla base64. |
| self.assertRaisesRegexp( |
| chromedriver.InvalidArgument, |
| 'credentialId must be a base64url encoded string', |
| self._driver.AddCredential, authenticatorId, '_0n+wWqg=', |
| False, "chromedriver.test", self.privateKey, None, 1, |
| ) |
| |
| # Try adding a credentialId that is not a string. |
| self.assertRaisesRegexp( |
| chromedriver.InvalidArgument, |
| 'credentialId must be a base64url encoded string', |
| self._driver.AddCredential, authenticatorId, 1, |
| False, "chromedriver.test", self.privateKey, None, 1, |
| ) |
| |
| def testGetCredentials(self): |
| script = """ |
| let done = arguments[0]; |
| registerCredential({ |
| authenticatorSelection: { |
| requireResidentKey: true, |
| }, |
| }).then(done); |
| """ |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| authenticatorId = self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| hasResidentKey = True, |
| hasUserVerification = True, |
| isUserVerified = True, |
| ) |
| |
| # Register a credential via the webauthn API. |
| result = self._driver.ExecuteAsyncScript(script) |
| self.assertEquals('OK', result['status']) |
| credentialId = result['credential']['id'] |
| |
| # GetCredentials should return the credential that was just created. |
| credentials = self._driver.GetCredentials(authenticatorId) |
| self.assertEquals(1, len(credentials)) |
| self.assertEquals(credentialId, credentials[0]['credentialId']) |
| self.assertEquals(True, credentials[0]['isResidentCredential']) |
| self.assertEquals('chromedriver.test', credentials[0]['rpId']) |
| self.assertEquals(chr(1), |
| self.UrlSafeBase64Decode(credentials[0]['userHandle'])) |
| self.assertEquals(1, credentials[0]['signCount']) |
| self.assertTrue(credentials[0]['privateKey']) |
| |
| def testRemoveCredential(self): |
| script = """ |
| let done = arguments[0]; |
| registerCredential().then(done); |
| """ |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| authenticatorId = self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| ) |
| |
| # Register two credentials. |
| result = self._driver.ExecuteAsyncScript(script) |
| self.assertEquals('OK', result['status']) |
| credential1Id = result['credential']['id'] |
| |
| result = self._driver.ExecuteAsyncScript(script) |
| self.assertEquals('OK', result['status']) |
| credential2Id = result['credential']['id'] |
| |
| # GetCredentials should return both credentials. |
| credentials = self._driver.GetCredentials(authenticatorId) |
| self.assertEquals(2, len(credentials)) |
| |
| # Removing the first credential should leave only the first one. |
| self._driver.RemoveCredential(authenticatorId, credential1Id) |
| credentials = self._driver.GetCredentials(authenticatorId) |
| self.assertEquals(1, len(credentials)) |
| self.assertEquals(credential2Id, credentials[0]['credentialId']) |
| |
| def testRemoveAllCredentials(self): |
| register_credential_script = """ |
| let done = arguments[0]; |
| registerCredential().then(done); |
| """ |
| self._driver.Load(self.GetHttpsUrlForFile( |
| '/chromedriver/webauthn_test.html', 'chromedriver.test')) |
| authenticatorId = self._driver.AddVirtualAuthenticator( |
| protocol = 'ctap2', |
| transport = 'usb', |
| ) |
| |
| |