Browsermanagement
Browsermanagement
import time
import types
from datetime import timedelta
from typing import Optional, Union, Any, List
class BrowserManagementKeywords(LibraryComponent):
def __init__(self, ctx):
LibraryComponent.__init__(self, ctx)
self._window_manager = WindowManager(ctx)
self._webdriver_creator = WebDriverCreator(self.log_dir)
@keyword
def close_all_browsers(self):
"""Closes all open browsers and resets the browser cache.
After this keyword, new indexes returned from `Open Browser` keyword
are reset to 1.
@keyword
def close_browser(self):
"""Closes the current browser."""
if self.drivers.current:
self.debug(f"Closing browser with session id
{self.driver.session_id}.")
self.drivers.close()
@keyword
def open_browser(
self,
url: Optional[str] = None,
browser: str = "firefox",
alias: Optional[str] = None,
remote_url: Union[bool, str] = False,
desired_capabilities: Union[dict, None, str] = None,
ff_profile_dir: Union[FirefoxProfile, str, None] = None,
options: Any = None,
service_log_path: Optional[str] = None,
executable_path: Optional[str] = None,
service: Any = None,
) -> str:
"""Opens a new browser instance to the optional ``url``.
| = Browser = | = Name(s) = |
| Firefox | firefox, ff |
| Google Chrome | googlechrome, chrome, gc |
| Headless Firefox | headlessfirefox |
| Headless Chrome | headlesschrome |
| Internet Explorer | internetexplorer, ie |
| Edge | edge |
| Safari | safari |
Examples:
| `Open Browser` | http://example.com | Chrome |
|
| `Open Browser` | http://example.com | Firefox | alias=Firefox
|
| `Open Browser` | http://example.com | Edge |
remote_url=http://127.0.0.1:4444/wd/hub |
| `Open Browser` | about:blank | |
|
| `Open Browser` | browser=Chrome | |
|
Alias examples:
| ${1_index} = | `Open Browser` | http://example.com | Chrome |
alias=Chrome | # Opens new browser because alias is new. |
| ${2_index} = | `Open Browser` | http://example.com | Firefox |
| # Opens new browser because alias is not defined. |
| ${3_index} = | `Open Browser` | http://example.com | Chrome |
alias=Chrome | # Switches to the browser with Chrome alias. |
| ${4_index} = | `Open Browser` | http://example.com | Chrome |
alias=${1_index} | # Switches to the browser with Chrome alias. |
| Should Be Equal | ${1_index} | ${3_index} | |
| |
| Should Be Equal | ${1_index} | ${4_index} | |
| |
| Should Be Equal | ${2_index} | ${2} | |
| |
The string format uses a Python like syntax to define Selenium options
methods or attributes.
See the `Browser and Driver options` section for more details on how to use
the either the string format or Python object syntax with the ``options``
argument.
def _make_new_browser(
self,
url=None,
browser="firefox",
alias=None,
remote_url=False,
desired_capabilities=None,
ff_profile_dir=None,
options=None,
service_log_path=None,
executable_path=None,
service=None,
):
if remote_url:
self.info(
f"Opening browser '{browser}' to base url '{url}' through "
f"remote server at '{remote_url}'."
)
else:
self.info(f"Opening browser '{browser}' to base url '{url}'.")
driver = self._make_driver(
browser,
desired_capabilities,
ff_profile_dir,
remote_url,
options,
service_log_path,
executable_path,
service,
)
driver = self._wrap_event_firing_webdriver(driver)
index = self.ctx.register_driver(driver, alias)
if url:
try:
driver.get(url)
except Exception:
self.debug(
f"Opened browser with session id {driver.session_id} but failed
to open url '{url}'."
)
raise
self.debug(f"Opened browser with session id {driver.session_id}.")
return index
@keyword
def create_webdriver(
self, driver_name: str, alias: Optional[str] = None, kwargs: Optional[dict]
= None, **init_kwargs
) -> str:
"""Creates an instance of Selenium WebDriver.
Examples:
| # Use proxy with Firefox | |
| |
| ${proxy}= | `Evaluate` | selenium.webdriver.Proxy()
| modules=selenium, selenium.webdriver |
| ${proxy.http_proxy}= | `Set Variable` | localhost:8888
| |
| `Create Webdriver` | Firefox | proxy=${proxy}
| |
Returns the index of this browser instance which can be used later to
switch back to it. Index starts from 1 and is reset back to it when
`Close All Browsers` keyword is used. See `Switch Browser` for an
example.
"""
if kwargs is None:
kwargs = {}
if not isinstance(kwargs, dict):
raise RuntimeError("kwargs must be a dictionary.")
for arg_name in kwargs:
if arg_name in init_kwargs:
raise RuntimeError(f"Got multiple values for argument
'{arg_name}'.")
init_kwargs[arg_name] = kwargs[arg_name]
driver_name = driver_name.strip()
try:
creation_func = getattr(webdriver, driver_name)
except AttributeError:
raise RuntimeError(f"'{driver_name}' is not a valid WebDriver name.")
self.info(f"Creating an instance of the {driver_name} WebDriver.")
driver = creation_func(**init_kwargs)
self.debug(
f"Created {driver_name} WebDriver instance with session id
{driver.session_id}."
)
driver = self._wrap_event_firing_webdriver(driver)
return self.ctx.register_driver(driver, alias)
@keyword
def switch_browser(self, index_or_alias: str):
"""Switches between active browsers using ``index_or_alias``.
Indices are returned by the `Open Browser` keyword and aliases can
be given to it explicitly. Indices start from 1.
Example:
| `Open Browser` | http://google.com | ff |
| `Location Should Be` | http://google.com | |
| `Open Browser` | http://yahoo.com | ie | alias=second |
| `Location Should Be` | http://yahoo.com | |
| `Switch Browser` | 1 | # index |
| `Page Should Contain` | I'm feeling lucky | |
| `Switch Browser` | second | # alias |
| `Page Should Contain` | More Yahoo! | |
| `Close All Browsers` | | |
Above example expects that there was no other open browsers when
opening the first one because it used index ``1`` when switching to
it later. If you are not sure about that, you can store the index
into a variable as below.
@keyword
def get_browser_ids(self) -> List[str]:
"""Returns index of all active browser as list.
Example:
| @{browser_ids}= | Get Browser Ids | |
|
| FOR | ${id} | IN | @{browser_ids}
|
| | @{window_titles}= | Get Window Titles | browser=${id}
|
| | Log | Browser ${id} has these windows: $
{window_titles} | |
| END | | |
|
@keyword
def get_browser_aliases(self) -> List[str]:
"""Returns aliases of all active browser that has an alias as
NormalizedDict.
The dictionary contains the aliases as keys and the index as value.
This can be accessed as dictionary ``${aliases.key}`` or as list
``@{aliases}[0]``.
Example:
| `Open Browser` | https://example.com | alias=BrowserA | |
| `Open Browser` | https://example.com | alias=BrowserB | |
| &{aliases} | `Get Browser Aliases` | | # &{aliases} =
{ BrowserA=1|BrowserB=2 } |
| `Log` | ${aliases.BrowserA} | | # logs ``1`` |
| FOR | ${alias} | IN | @{aliases} |
| | `Log` | ${alias} | # logs
``BrowserA`` and ``BrowserB`` |
| END | | | |
@keyword
def get_session_id(self) -> str:
"""Returns the currently active browser session id.
@keyword
def get_source(self) -> str:
"""Returns the entire HTML source of the current page or frame."""
return self.driver.page_source
@keyword
def get_title(self) -> str:
"""Returns the title of the current page."""
return self.driver.title
@keyword
def get_location(self) -> str:
"""Returns the current browser window URL."""
return self.driver.current_url
@keyword
def location_should_be(self, url: str, message: Optional[str] = None):
"""Verifies that the current URL is exactly ``url``.
The ``url`` argument contains the exact url that should exist in browser.
@keyword
def location_should_contain(self, expected: str, message: Optional[str] =
None):
"""Verifies that the current URL contains ``expected``.
@keyword
def log_location(self) -> str:
"""Logs and returns the current browser window URL."""
url = self.get_location()
self.info(url)
return url
@keyword
def log_source(self, loglevel: str = "INFO") -> str:
"""Logs and returns the HTML source of the current page or frame.
The ``loglevel`` argument defines the used log level. Valid log
levels are ``WARN``, ``INFO`` (default), ``DEBUG``, ``TRACE``
and ``NONE`` (no logging).
"""
source = self.get_source()
self.log(source, loglevel)
return source
@keyword
def log_title(self) -> str:
"""Logs and returns the title of the current page."""
title = self.get_title()
self.info(title)
return title
@keyword
def title_should_be(self, title: str, message: Optional[str] = None):
"""Verifies that the current page title equals ``title``.
@keyword
def go_back(self):
"""Simulates the user clicking the back button on their browser."""
self.driver.back()
@keyword
def go_to(self, url):
"""Navigates the current browser window to the provided ``url``."""
self.info(f"Opening url '{url}'")
self.driver.get(url)
@keyword
def reload_page(self):
"""Simulates user reloading page."""
self.driver.refresh()
@keyword
def get_selenium_speed(self) -> str:
"""Gets the delay that is waited after each Selenium command.
@keyword
def get_selenium_timeout(self) -> str:
"""Gets the timeout that is used by various keywords.
@keyword
def get_selenium_implicit_wait(self) -> str:
"""Gets the implicit wait value used by Selenium.
@keyword
def get_selenium_page_load_timeout(self) -> str:
"""Gets the time to wait for a page load to complete
before raising a timeout exception.
@keyword
def set_selenium_speed(self, value: timedelta) -> str:
"""Sets the delay that is waited after each Selenium command.
Example:
| `Set Selenium Speed` | 0.5 seconds |
"""
old_speed = self.get_selenium_speed()
self.ctx.speed = _convert_timeout(value)
for driver in self.drivers.active_drivers:
self._monkey_patch_speed(driver)
return old_speed
@keyword
def set_selenium_timeout(self, value: timedelta) -> str:
"""Sets the timeout that is used by various keywords.
Example:
| ${orig timeout} = | `Set Selenium Timeout` | 15 seconds |
| `Open page that loads slowly` |
| `Set Selenium Timeout` | ${orig timeout} |
"""
old_timeout = self.get_selenium_timeout()
self.ctx.timeout = _convert_timeout(value)
for driver in self.drivers.active_drivers:
driver.set_script_timeout(self.ctx.timeout)
return old_timeout
@keyword
def set_selenium_implicit_wait(self, value: timedelta) -> str:
"""Sets the implicit wait value used by Selenium.
This keyword sets the implicit wait for all opened browsers.
Use `Set Browser Implicit Wait` to set it only to the current
browser.
Example:
| ${orig wait} = | `Set Selenium Implicit Wait` | 10 seconds |
| `Perform AJAX call that is slow` |
| `Set Selenium Implicit Wait` | ${orig wait} |
"""
old_wait = self.get_selenium_implicit_wait()
self.ctx.implicit_wait = _convert_timeout(value)
for driver in self.drivers.active_drivers:
driver.implicitly_wait(self.ctx.implicit_wait)
return old_wait
@keyword
def set_action_chain_delay(self, value: timedelta) -> str:
"""Sets the duration of delay in ActionChains() used by SeleniumLibrary.
@keyword
def get_action_chain_delay(self):
"""Gets the currently stored value for chain_delay_value in timestr format.
"""
return timestr_to_secs(f"{self.ctx.action_chain_delay} milliseconds")
@keyword
def set_browser_implicit_wait(self, value: timedelta):
"""Sets the implicit wait value used by Selenium.
Same as `Set Selenium Implicit Wait` but only affects the current
browser.
"""
self.driver.implicitly_wait(_convert_timeout(value))
@keyword
def set_selenium_page_load_timeout(self, value: timedelta) -> str:
"""Sets the page load timeout value used by Selenium.
Example:
| ${orig page load timeout} = | `Set Selenium Page Load Timeout` | 30
seconds |
| `Open page that loads slowly` |
| `Set Selenium Page Load Timeout` | ${orig page load timeout} |
def _make_driver(
self,
browser,
desired_capabilities=None,
profile_dir=None,
remote=None,
options=None,
service_log_path=None,
executable_path=None,
service=None,
):
driver = self._webdriver_creator.create_driver(
browser=browser,
desired_capabilities=desired_capabilities,
remote_url=remote,
profile_dir=profile_dir,
options=options,
service_log_path=service_log_path,
executable_path=executable_path,
service=service,
)
driver.set_script_timeout(self.ctx.timeout)
driver.implicitly_wait(self.ctx.implicit_wait)
driver.set_page_load_timeout(self.ctx.page_load_timeout)
if self.ctx.speed:
self._monkey_patch_speed(driver)
return driver