1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """Extended WebDriver interface that uses helper extension. 6 7 This file is makeshift and should eventually be switched over to 8 using the new ChromeDriver python interface. However, as that is 9 not quite ready, this class simply installs a helper extension 10 and executes scripts in the background page to access extension 11 APIs. 12 13 This may end up being merged with chrome/test/ext_auto, if they 14 accomplish similar enough purposes. For now, integration with that 15 is a bit premature. 16 """ 17 18 import os 19 20 from selenium import webdriver 21 22 23 _CHROME_GET_VIEW_HANDLES = 'chrome.getViewHandles' 24 _EXTENSION = os.path.join( 25 os.path.dirname(os.path.abspath(__file__)), 'ext_auto') 26 27 28 class Chrome(webdriver.Remote): 29 """Extended WebDriver interface that uses helper extension.""" 30 31 def __init__(self, url, desired_capabilities, options=None): 32 """Initializes Chrome object. 33 34 If both desired_capabilities and options have the same settings, the 35 settings from options will be used. 36 37 Args: 38 url: The URL of the ChromeDriver Service. 39 desired_capabilities: Chrome capabilities dictionary. 40 options: chrome_options.ChromeOptions object. Settings in options will 41 overwrite settings in desired_capabilities. 42 43 Raises: 44 RuntimeError: Unable to find helper extension. 45 """ 46 if options is not None: 47 desired_capabilities.update(options.GetCapabilities()) 48 switches = desired_capabilities.get('chrome.switches', []) 49 switches += ['--load-extension=' + _EXTENSION] 50 desired_capabilities['chrome.switches'] = switches 51 super(Chrome, self).__init__(url, desired_capabilities) 52 53 custom_commands = { 54 _CHROME_GET_VIEW_HANDLES: 55 ('GET', '/session/$sessionId/chrome/views'), 56 } 57 self.command_executor._commands.update(custom_commands) 58 views = self.execute(_CHROME_GET_VIEW_HANDLES)['value'] 59 self.set_script_timeout(30) # TODO(kkania): Make this configurable. 60 for view in views: 61 if view.get('extension_id') == 'aapnijgdinlhnhlmodcfapnahmbfebeb': 62 self._extension = view['handle'] 63 break 64 else: 65 raise RuntimeError('Unable to find helper extension') 66 67 def _execute_extension_command(self, name, params={}): 68 """Executes an extension command. 69 70 When Chrome is started, a helper extension is loaded which provides 71 a simple synchronous API for manipulating Chrome via the extension 72 APIs. Communication with the extension is accomplished by executing 73 a script in the background page of the extension which calls the 74 'executeCommand' function with the name of the command, a parameter 75 dictionary, and a callback function that can be used to signal 76 when the command is finished and potentially send a return value. 77 """ 78 old_window = self.current_window_handle 79 self.switch_to_window(self._extension) 80 self.execute_async_script( 81 'executeCommand.apply(null, arguments)', name, params) 82 self.switch_to_window(old_window) 83 84 def create_tab(self, url=None): 85 """Creates a new tab with the given URL and switches to it. 86 87 If no URL is provided, the homepage will be used. 88 """ 89 params = {} 90 if url is not None: 91 params['url'] = url 92 self._execute_extension_command('createTab', params) 93 self.switch_to_window(self.window_handles[-1]) 94 95 def create_blank_tab(self): 96 """Creates a new blank tab and switches to it.""" 97 self.create_tab('about:blank') 98