Robot Framework SeleniumLibrary
webdrivertools.py
Go to the documentation of this file.
1 # Copyright 2008-2011 Nokia Networks
2 # Copyright 2011-2016 Ryan Tomac, Ed Manlove and contributors
3 # Copyright 2016- Robot Framework Foundation
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 import inspect
17 import os
18 import warnings
19 
20 from robot.api import logger
21 from robot.utils import ConnectionCache
22 from selenium import webdriver
23 
24 from SeleniumLibrary.utils import is_falsy, is_truthy, is_noney
25 
26 
28 
29  browser_names = {
30  'googlechrome': "chrome",
31  'gc': "chrome",
32  'chrome': "chrome",
33  'headlesschrome': 'headless_chrome',
34  'ff': 'firefox',
35  'firefox': 'firefox',
36  'headlessfirefox': 'headless_firefox',
37  'ie': 'ie',
38  'internetexplorer': 'ie',
39  'edge': 'edge',
40  'opera': 'opera',
41  'safari': 'safari',
42  'phantomjs': 'phantomjs',
43  'htmlunit': 'htmlunit',
44  'htmlunitwithjs': 'htmlunit_with_js',
45  'android': 'android',
46  'iphone': 'iphone'
47  }
48 
49  def __init__(self, log_dir):
50  self.log_dirlog_dir = log_dir
51 
52  def create_driver(self, browser, desired_capabilities, remote_url,
53  profile_dir=None, service_log_path=None):
54  creation_method = self._get_creator_method_get_creator_method(browser)
55  desired_capabilities = self._parse_capabilities_parse_capabilities(desired_capabilities, browser)
56  service_log_path = self._get_log_path_get_log_path(service_log_path)
57  if service_log_path:
58  logger.info('Browser driver log file created to: %s' % service_log_path)
59  self._create_directory_create_directory(service_log_path)
60  if (creation_method == self.create_firefoxcreate_firefox
61  or creation_method == self.create_headless_firefoxcreate_headless_firefox):
62  return creation_method(desired_capabilities, remote_url,
63  profile_dir, service_log_path=service_log_path)
64  return creation_method(desired_capabilities, remote_url, service_log_path=service_log_path)
65 
66  def _get_creator_method(self, browser):
67  browser = browser.lower().replace(' ', '')
68  if browser in self.browser_namesbrowser_names:
69  return getattr(self, 'create_{}'.format(self.browser_namesbrowser_names[browser]))
70  raise ValueError('{} is not a supported browser.'.format(browser))
71 
72  def _parse_capabilities(self, capabilities, browser=None):
73  if is_falsy(capabilities):
74  return {}
75  if not isinstance(capabilities, dict):
76  capabilities = self._string_to_dict_string_to_dict(capabilities)
77  browser = self.browser_namesbrowser_names.get(browser, browser)
78  if browser in ['ie', 'firefox', 'edge']:
79  return {'capabilities': capabilities}
80  return {'desired_capabilities': capabilities}
81 
82  def _string_to_dict(self, capabilities):
83  desired_capabilities = {}
84  for part in capabilities.split(','):
85  key, value = part.split(':')
86  desired_capabilities[key.strip()] = value.strip()
87  return desired_capabilities
88 
89  def _remote_capabilities_resolver(self, set_capabilities, default_capabilities):
90  if not set_capabilities:
91  return {'desired_capabilities': default_capabilities}
92  if 'capabilities' in set_capabilities:
93  caps = set_capabilities['capabilities']
94  else:
95  caps = set_capabilities['desired_capabilities']
96  if 'browserName' not in caps:
97  caps['browserName'] = default_capabilities['browserName']
98  return {'desired_capabilities': caps}
99 
100  def create_chrome(self, desired_capabilities, remote_url, options=None, service_log_path=None):
101  if is_truthy(remote_url):
102  defaul_caps = webdriver.DesiredCapabilities.CHROME.copy()
103  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
104  return self._remote_remote(desired_capabilities, remote_url, options=options)
105  return webdriver.Chrome(options=options, service_log_path=service_log_path, **desired_capabilities)
106 
107  def create_headless_chrome(self, desired_capabilities, remote_url, service_log_path=None):
108  options = webdriver.ChromeOptions()
109  # Can be changed to options.headless = True when minimum Selenium version is 3.12.0 or greater.
110  options.set_headless()
111  return self.create_chromecreate_chrome(desired_capabilities, remote_url, options, service_log_path)
112 
113  def create_firefox(self, desired_capabilities, remote_url, ff_profile_dir, options=None, service_log_path=None):
114  profile = self._get_ff_profile_get_ff_profile(ff_profile_dir)
115  if is_truthy(remote_url):
116  defaul_caps = webdriver.DesiredCapabilities.FIREFOX.copy()
117  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
118  return self._remote_remote(desired_capabilities, remote_url,
119  profile, options)
120  service_log_path = service_log_path if service_log_path else self._geckodriver_log_geckodriver_log_geckodriver_log
121  return webdriver.Firefox(options=options, firefox_profile=profile, service_log_path=service_log_path,
122  **desired_capabilities)
123 
124  def _get_ff_profile(self, ff_profile_dir):
125  if is_falsy(ff_profile_dir):
126  return webdriver.FirefoxProfile()
127  return webdriver.FirefoxProfile(ff_profile_dir)
128 
129  @property
130  _geckodriver_log = property
131 
132  def _geckodriver_log(self):
133  log_file = self._get_log_path_get_log_path(os.path.join(self.log_dirlog_dir, 'geckodriver-{index}.log'))
134  logger.info('Firefox driver log is always forced to to: %s' % log_file)
135  return log_file
136 
137  def create_headless_firefox(self, desired_capabilities, remote_url,
138  ff_profile_dir, service_log_path=None):
139  options = webdriver.FirefoxOptions()
140  # Can be changed to options.headless = True when minimum Selenium version is 3.12.0 or greater.
141  options.set_headless()
142  return self.create_firefoxcreate_firefox(desired_capabilities, remote_url, ff_profile_dir, options, service_log_path)
143 
144  def create_ie(self, desired_capabilities, remote_url, service_log_path=None):
145  if is_truthy(remote_url):
146  defaul_caps = webdriver.DesiredCapabilities.INTERNETEXPLORER.copy()
147  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
148  return self._remote_remote(desired_capabilities, remote_url)
149  if self._has_service_log_path_has_service_log_path(webdriver.Ie):
150  return webdriver.Ie(service_log_path=service_log_path, **desired_capabilities)
151  logger.warn('This version of Selenium does not support service_log_path argument.')
152  return webdriver.Ie(**desired_capabilities)
153 
154  def _has_service_log_path(self, web_driver):
155  signature = inspect.getargspec(web_driver.__init__)
156  return True if 'service_log_path' in signature.args else False
157 
158  def create_edge(self, desired_capabilities, remote_url, service_log_path=None):
159  if is_truthy(remote_url):
160  defaul_caps = webdriver.DesiredCapabilities.EDGE.copy()
161  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
162  return self._remote_remote(desired_capabilities, remote_url)
163  if self._has_service_log_path_has_service_log_path(webdriver.Ie):
164  return webdriver.Edge(service_log_path=service_log_path, **desired_capabilities)
165  logger.warn('This version of Selenium does not support service_log_path argument.')
166  return webdriver.Edge(**desired_capabilities)
167 
168  def create_opera(self, desired_capabilities, remote_url, service_log_path=None):
169  if is_truthy(remote_url):
170  defaul_caps = webdriver.DesiredCapabilities.OPERA.copy()
171  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
172  return self._remote_remote(desired_capabilities, remote_url)
173  return webdriver.Opera(service_log_path=service_log_path, **desired_capabilities)
174 
175  def create_safari(self, desired_capabilities, remote_url):
176  if is_truthy(remote_url):
177  defaul_caps = webdriver.DesiredCapabilities.SAFARI.copy()
178  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
179  return self._remote_remote(desired_capabilities, remote_url)
180  return webdriver.Safari(**desired_capabilities)
181 
182  def create_phantomjs(self, desired_capabilities, remote_url, service_log_path=None):
183  warnings.warn('SeleniumLibrary support for PhantomJS has been deprecated, '
184  'please use headlesschrome or headlessfirefox instead.')
185  if is_truthy(remote_url):
186  defaul_caps = webdriver.DesiredCapabilities.PHANTOMJS.copy()
187  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
188  return self._remote_remote(desired_capabilities, remote_url)
189  return webdriver.PhantomJS(service_log_path=service_log_path, **desired_capabilities)
190 
191  def create_htmlunit(self, desired_capabilities, remote_url, service_log_path=None):
192  if service_log_path:
193  logger.warn('Htmlunit does not support service_log_path argument.')
194  defaul_caps = webdriver.DesiredCapabilities.HTMLUNIT.copy()
195  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
196  return self._remote_remote(desired_capabilities, remote_url)
197 
198  def create_htmlunit_with_js(self, desired_capabilities, remote_url, service_log_path=None):
199  if service_log_path:
200  logger.warn('Htmlunit does not support service_log_path argument.')
201  defaul_caps = webdriver.DesiredCapabilities.HTMLUNITWITHJS.copy()
202  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
203  return self._remote_remote(desired_capabilities, remote_url)
204 
205  def create_android(self, desired_capabilities, remote_url, service_log_path=None):
206  if service_log_path:
207  logger.warn('Android does not support service_log_path argument.')
208  defaul_caps = webdriver.DesiredCapabilities.ANDROID.copy()
209  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
210  return self._remote_remote(desired_capabilities, remote_url)
211 
212  def create_iphone(self, desired_capabilities, remote_url, service_log_path=None):
213  if service_log_path:
214  logger.warn('iPhone does not support service_log_path argument.')
215  defaul_caps = webdriver.DesiredCapabilities.IPHONE.copy()
216  desired_capabilities = self._remote_capabilities_resolver_remote_capabilities_resolver(desired_capabilities, defaul_caps)
217  return self._remote_remote(desired_capabilities, remote_url)
218 
219  def _remote(self, desired_capabilities, remote_url,
220  profile_dir=None, options=None):
221  remote_url = str(remote_url)
222  return webdriver.Remote(command_executor=remote_url,
223  browser_profile=profile_dir, options=options,
224  **desired_capabilities)
225 
226  def _get_log_path(self, log_file):
227  if is_noney(log_file):
228  return None
229  index = 1
230  while True:
231  formatted = log_file.format(index=index)
232  path = os.path.join(self.log_dirlog_dir, formatted)
233  # filename didn't contain {index} or unique path was found
234  if formatted == log_file or not os.path.exists(path):
235  return path
236  index += 1
237 
238  def _create_directory(self, path):
239  target_dir = os.path.dirname(path)
240  if not os.path.exists(target_dir):
241  os.makedirs(target_dir)
242 
243 
244 class WebDriverCache(ConnectionCache):
245 
246  def __init__(self):
247  ConnectionCache.__init__(self, no_current_msg='No current browser')
248  self._closed_closed = set()
249 
250  @property
251  drivers = property
252 
253  def drivers(self):
254  return self._connections
255 
256  @property
257  active_drivers = property
258 
259  def active_drivers(self):
260  open_drivers = []
261  for driver in self._connections:
262  if driver not in self._closed_closed:
263  open_drivers.append(driver)
264  return open_drivers
265 
266  def close(self):
267  if self.currentcurrent:
268  driver = self.currentcurrent
269  error = self._quit_quit(driver, None)
270  self.currentcurrent = self._no_current
271  self._closed_closed.add(driver)
272  if error:
273  raise error
274 
275  def close_all(self):
276  error = None
277  for driver in self._connections:
278  if driver not in self._closed_closed:
279  error = self._quit_quit(driver, error)
280  self.empty_cache()
281  if error:
282  raise error
283  return self.currentcurrent
284 
285  def _quit(self, driver, error):
286  try:
287  driver.quit()
288  except Exception as exception:
289  logger.error('When closing browser, received exception: %s' % exception)
290  error = exception
291  return error
292 
293  def get_index(self, alias_or_index):
294  index = self._get_index_get_index(alias_or_index)
295  try:
296  driver = self.get_connection(index)
297  except RuntimeError:
298  return None
299  return None if driver in self._closed_closed else index
300 
301  def _get_index(self, alias_or_index):
302  alias_or_index = None if is_noney(alias_or_index) else alias_or_index
303  try:
304  return self.resolve_alias_or_index(alias_or_index)
305  except AttributeError:
306  pass
307  except ValueError:
308  return None
309  # TODO: This try/except block can be removed when minimum
310  # required Robot Framework version is 3.3 or greater.
311  try:
312  return self._resolve_alias_or_index(alias_or_index)
313  except ValueError:
314  return None
def _remote_capabilities_resolver(self, set_capabilities, default_capabilities)
def create_chrome(self, desired_capabilities, remote_url, options=None, service_log_path=None)
def create_safari(self, desired_capabilities, remote_url)
def create_phantomjs(self, desired_capabilities, remote_url, service_log_path=None)
def create_driver(self, browser, desired_capabilities, remote_url, profile_dir=None, service_log_path=None)
def create_htmlunit_with_js(self, desired_capabilities, remote_url, service_log_path=None)
def _parse_capabilities(self, capabilities, browser=None)
def create_headless_chrome(self, desired_capabilities, remote_url, service_log_path=None)
def create_headless_firefox(self, desired_capabilities, remote_url, ff_profile_dir, service_log_path=None)
def create_iphone(self, desired_capabilities, remote_url, service_log_path=None)
def create_htmlunit(self, desired_capabilities, remote_url, service_log_path=None)
def create_opera(self, desired_capabilities, remote_url, service_log_path=None)
def _remote(self, desired_capabilities, remote_url, profile_dir=None, options=None)
def create_android(self, desired_capabilities, remote_url, service_log_path=None)
def create_ie(self, desired_capabilities, remote_url, service_log_path=None)
def create_edge(self, desired_capabilities, remote_url, service_log_path=None)
def create_firefox(self, desired_capabilities, remote_url, ff_profile_dir, options=None, service_log_path=None)