get_webelements
def get_webelements(self, locator: Union[WebElement, str]) -> WebElement:
return self.find_elements(locator)
element_should_contain
def element_should_contain(
self,
locator: Union[WebElement, str],
expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
):
actual = actual_before = self.find_element(locator).text
expected_before = expected
if ignore_case:
actual = actual.lower()
expected = expected.lower()
if expected not in actual:
if message is None:
message = (
f"Element '{locator}' should have contained text '{expected_before}' but "
f"its text was '{actual_before}'."
)
raise AssertionError(message)
self.info(f"Element '{locator}' contains text '{expected_before}'.")
element_should_not_contain
def element_should_not_contain(
self,
locator: Union[WebElement, str],
expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
):
actual = self.find_element(locator).text
expected_before = expected
if ignore_case:
actual = actual.lower()
expected = expected.lower()
if expected in actual:
if message is None:
message = (
f"Element '{locator}' should not contain text '{expected_before}' but "
"it did."
)
raise AssertionError(message)
self.info(f"Element '{locator}' does not contain text '{expected_before}'.")
page_should_contain
def page_should_contain(self, text: str, loglevel: str = "TRACE"):
if not self._page_contains(text):
self.ctx.log_source(loglevel)
raise AssertionError(
f"Page should have contained text '{text}' but did not."
)
self.info(f"Current page contains text '{text}'.")
page_should_contain_element
def page_should_contain_element(
self,
locator: Union[WebElement, str],
message: Optional[str] = None,
loglevel: str = "TRACE",
limit: Optional[int] = None,
):
if limit is None:
return self.assert_page_contains(
locator, message=message, loglevel=loglevel
)
count = len(self.find_elements(locator))
if count == limit:
self.info(f"Current page contains {count} element(s).")
else:
if message is None:
message = (
f'Page should have contained "{limit}" element(s), '
f'but it did contain "{count}" element(s).'
)
self.ctx.log_source(loglevel)
raise AssertionError(message)
page_should_not_contain
def page_should_not_contain(self, text: str, loglevel: str = "TRACE"):
"""Verifies the current page does not contain ``text``.
See `Page Should Contain` for an explanation about the ``loglevel``
argument.
"""
if self._page_contains(text):
self.ctx.log_source(loglevel)
raise AssertionError(f"Page should not have contained text '{text}'.")
self.info(f"Current page does not contain text '{text}'.")
page_should_not_contain_element
def page_should_not_contain_element(
self,
locator: Union[WebElement, str],
message: Optional[str] = None,
loglevel: str = "TRACE",
):
"""Verifies that element ``locator`` is not found on the current page.
See the `Locating elements` section for details about the locator
syntax.
See `Page Should Contain` for an explanation about ``message`` and
``loglevel`` arguments.
"""
self.assert_page_not_contains(locator, message=message, loglevel=loglevel)
element_should_be_disabled
def element_should_be_disabled(self, locator: Union[WebElement, str]):
"""Verifies that element identified by ``locator`` is disabled.
This keyword considers also elements that are read-only to be
disabled.
See the `Locating elements` section for details about the locator
syntax.
"""
if self.is_element_enabled(locator):
raise AssertionError(f"Element '{locator}' is enabled.")
element_should_be_enabled
def element_should_be_enabled(self, locator: Union[WebElement, str]):
"""Verifies that element identified by ``locator`` is enabled.
This keyword considers also elements that are read-only to be
disabled.
See the `Locating elements` section for details about the locator
syntax.
"""
if not self.is_element_enabled(locator):
raise AssertionError(f"Element '{locator}' is disabled.")
element_should_be_focused
def element_should_be_focused(self, locator: Union[WebElement, str]):
"""Verifies that element identified by ``locator`` is focused.
See the `Locating elements` section for details about the locator
syntax.
New in SeleniumLibrary 3.0.
"""
element = self.find_element(locator)
focused = self.driver.switch_to.active_element
# Selenium 3.6.0 with Firefox return dict which contains the selenium WebElement
if isinstance(focused, dict):
focused = focused["value"]
if element != focused:
raise AssertionError(f"Element '{locator}' does not have focus.")
element_should_be_visible
def element_should_be_visible(
self, locator: Union[WebElement, str], message: Optional[str] = None
):
"""Verifies that the element identified by ``locator`` is visible.
Herein, visible means that the element is logically visible, not
optically visible in the current browser viewport. For example,
an element that carries ``display:none`` is not logically visible,
so using this keyword on that element would fail.
See the `Locating elements` section for details about the locator
syntax.
The ``message`` argument can be used to override the default error
message.
"""
if not self.find_element(locator).is_displayed():
if message is None:
message = f"The element '{locator}' should be visible, but it is not."
raise AssertionError(message)
self.info(f"Element '{locator}' is displayed.")
element_should_not_be_visible
def element_should_not_be_visible(
self, locator: Union[WebElement, str], message: Optional[str] = None
):
"""Verifies that the element identified by ``locator`` is NOT visible.
Passes if the element does not exists. See `Element Should Be Visible`
for more information about visibility and supported arguments.
"""
element = self.find_element(locator, required=False)
if element is None:
self.info(f"Element '{locator}' did not exist.")
elif not element.is_displayed():
self.info(f"Element '{locator}' exists but is not displayed.")
else:
if message is None:
message = f"The element '{locator}' should not be visible, but it is."
raise AssertionError(message)
element_text_should_be
def element_text_should_be(
self,
locator: Union[WebElement, str],
expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
):
"""Verifies that element ``locator`` contains exact the text ``expected``.
See the `Locating elements` section for details about the locator
syntax.
The ``message`` argument can be used to override the default error
message.
The ``ignore_case`` argument can be set to True to compare case
insensitive, default is False.
``ignore_case`` argument is new in SeleniumLibrary 3.1.
Use `Element Should Contain` if a substring match is desired.
"""
self.info(f"Verifying element '{locator}' contains exact text '{expected}'.")
text = before_text = self.find_element(locator).text
if ignore_case:
text = text.lower()
expected = expected.lower()
if text != expected:
if message is None:
message = (
f"The text of element '{locator}' should have been '{expected}' "
f"but it was '{before_text}'."
)
raise AssertionError(message)
element_text_should_not_be
def element_text_should_not_be(
self,
locator: Union[WebElement, str],
not_expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
):
"""Verifies that element ``locator`` does not contain exact the text ``not_expected``.
See the `Locating elements` section for details about the locator
syntax.
The ``message`` argument can be used to override the default error
message.
The ``ignore_case`` argument can be set to True to compare case
insensitive, default is False.
New in SeleniumLibrary 3.1.1
"""
self.info(
f"Verifying element '{locator}' does not contain exact text '{not_expected}'."
)
text = self.find_element(locator).text
before_not_expected = not_expected
if ignore_case:
text = text.lower()
not_expected = not_expected.lower()
if text == not_expected:
if message is None:
message = f"The text of element '{locator}' was not supposed to be '{before_not_expected}'."
raise AssertionError(message)
element_attribute_value_should_be
def element_attribute_value_should_be(
self,
locator: Union[WebElement, str],
attribute: str,
expected: Union[None, str],
message: Optional[str] = None,
):
"""Verifies element identified by ``locator`` contains expected attribute value.
See the `Locating elements` section for details about the locator
syntax.
Example:
`Element Attribute Value Should Be` | css:img | href | value
New in SeleniumLibrary 3.2.
"""
current_expected = self.find_element(locator).get_attribute(attribute)
if current_expected != expected:
if message is None:
message = (
f"Element '{locator}' attribute should have value '{expected}' "
f"({type_converter(expected)}) but its value was '{current_expected}' "
f"({type_converter(current_expected)})."
)
raise AssertionError(message)
self.info(
f"Element '{locator}' attribute '{attribute}' contains value '{expected}'."
)
get_element_attribute
def get_element_attribute(
self, locator: Union[WebElement, str], attribute: str
) -> str:
"""Returns the value of ``attribute`` from the element ``locator``.
See the `Locating elements` section for details about the locator
syntax.
Example:
| ${id}= | `Get Element Attribute` | css:h1 | id |
Passing attribute name as part of the ``locator`` was removed
in SeleniumLibrary 3.2. The explicit ``attribute`` argument
should be used instead.
"""
return self.find_element(locator).get_attribute(attribute)
get_horizontal_position
def get_horizontal_position(self, locator: Union[WebElement, str]) -> int:
"""Returns the horizontal position of the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
The position is returned in pixels off the left side of the page,
as an integer.
See also `Get Vertical Position`.
"""
return self.find_element(locator).location["x"]
get_element_size
def get_element_size(self, locator: Union[WebElement, str]) -> Tuple[int, int]:
"""Returns width and height of the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
Both width and height are returned as integers.
Example:
| ${width} | ${height} = | `Get Element Size` | css:div#container |
"""
element = self.find_element(locator)
return element.size["width"], element.size["height"]
get_value
def get_value(self, locator: Union[WebElement, str]) -> str:
"""Returns the value attribute of the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
"""
return self.get_element_attribute(locator, "value")
def clear_element_text(self, locator: Union[WebElement, str]):
"""Clears the value of the text-input-element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
"""
self.find_element(locator).clear()
clear_element_text
def get_text(self, locator: Union[WebElement, str]) -> str:
"""Returns the text value of the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
"""
return self.find_element(locator).text
get_vertical_position
def get_vertical_position(self, locator: Union[WebElement, str]) -> int:
"""Returns the vertical position of the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
The position is returned in pixels off the top of the page,
as an integer.
See also `Get Horizontal Position`.
"""
return self.find_element(locator).location["y"]
click_button
def click_button(
self, locator: Union[WebElement, str], modifier: Union[bool, str] = False
):
"""Clicks the button identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax. When using the default locator strategy, buttons are
searched using ``id``, ``name``, and ``value``.
See the `Click Element` keyword for details about the
``modifier`` argument.
The ``modifier`` argument is new in SeleniumLibrary 3.3
"""
if not modifier:
self.info(f"Clicking button '{locator}'.")
element = self.find_element(locator, tag="input", required=False)
if not element:
element = self.find_element(locator, tag="button")
element.click()
else:
self._click_with_modifier(locator, ["button", "input"], modifier)
click_image
def click_image(
self, locator: Union[WebElement, str], modifier: Union[bool, str] = False
):
"""Clicks an image identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax. When using the default locator strategy, images are searched
using ``id``, ``name``, ``src`` and ``alt``.
See the `Click Element` keyword for details about the
``modifier`` argument.
The ``modifier`` argument is new in SeleniumLibrary 3.3
"""
if not modifier:
self.info(f"Clicking image '{locator}'.")
element = self.find_element(locator, tag="image", required=False)
if not element:
# A form may have an image as it's submit trigger.
element = self.find_element(locator, tag="input")
element.click()
else:
self._click_with_modifier(locator, ["image", "input"], modifier)
click_link
def click_link(
self, locator: Union[WebElement, str], modifier: Union[bool, str] = False
):
"""Clicks a link identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax. When using the default locator strategy, links are searched
using ``id``, ``name``, ``href`` and the link text.
See the `Click Element` keyword for details about the
``modifier`` argument.
The ``modifier`` argument is new in SeleniumLibrary 3.3
"""
if not modifier:
self.info(f"Clicking link '{locator}'.")
self.find_element(locator, tag="link").click()
else:
self._click_with_modifier(locator, ["link", "link"], modifier)
click_element
def click_element(
self,
locator: Union[WebElement, str],
modifier: Union[bool, str] = False,
action_chain: bool = False,
):
if is_truthy(modifier):
self._click_with_modifier(locator, [None, None], modifier)
elif action_chain:
self._click_with_action_chain(locator)
else:
self.info(f"Clicking element '{locator}'.")
self.find_element(locator).click()
_click_with_action_chain /_click_with_modifier
def _click_with_action_chain(self, locator: Union[WebElement, str]):
self.info(f"Clicking '{locator}' using an action chain.")
action = ActionChains(self.driver)
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
action.move_to_element(element)
action.click()
action.perform()
def _click_with_modifier(self, locator, tag, modifier):
self.info(
f"Clicking {tag if tag[0] else 'element'} '{locator}' with {modifier}."
)
modifier = self.parse_modifier(modifier)
action = ActionChains(self.driver)
for item in modifier:
action.key_down(item)
element = self.find_element(locator, tag=tag[0], required=False)
if not element:
element = self.find_element(locator, tag=tag[1])
element = _unwrap_eventfiring_element(element)
action.click(element)
for item in modifier:
action.key_up(item)
action.perform()
click_element_at_coordinates
def click_element_at_coordinates(
self, locator: Union[WebElement, str], xoffset: int, yoffset: int
):
self.info(
f"Clicking element '{locator}' at coordinates x={xoffset}, y={yoffset}."
)
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.move_to_element(element)
action.move_by_offset(xoffset, yoffset)
action.click()
action.perform()
double_click_element
def double_click_element(self, locator: Union[WebElement, str]):
"""Double clicks the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
"""
self.info(f"Double clicking element '{locator}'.")
element = self.find_element(locator)
# _unwrap_eventfiring_element can be removed when minimum required Selenium is 4.0 or greater.
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.double_click(element).perform()
set_focus_to_element
def set_focus_to_element(self, locator: Union[WebElement, str]):
"""Sets the focus to the element identified by ``locator``.
See the `Locating elements` section for details about the locator
syntax.
Prior to SeleniumLibrary 3.0 this keyword was named `Focus`.
"""
element = self.find_element(locator)
self.driver.execute_script("arguments[0].focus();", element)
scroll_element_into_view
def scroll_element_into_view(self, locator: Union[WebElement, str]):
"""Scrolls the element identified by ``locator`` into view.
See the `Locating elements` section for details about the locator
syntax.
New in SeleniumLibrary 3.2.0
"""
element = self.find_element(locator)
# _unwrap_eventfiring_element can be removed when minimum required Selenium is 4.0 or greater.
element = _unwrap_eventfiring_element(element)
ActionChains(self.driver).move_to_element(element).perform()
drag_and_drop
def drag_and_drop(
self, locator: Union[WebElement, str], target: Union[WebElement, str]
):
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
target = self.find_element(target)
target = _unwrap_eventfiring_element(target)
action = ActionChains(self.driver)
action.drag_and_drop(element, target).perform()
drag_and_drop_by_offset
def drag_and_drop_by_offset(
self, locator: Union[WebElement, str], xoffset: int, yoffset: int
):
"""Drags the element identified with ``locator`` by ``xoffset/yoffset``.
See the `Locating elements` section for details about the locator
syntax.
The element will be moved by ``xoffset`` and ``yoffset``, each of which
is a negative or positive number specifying the offset.
Example:
| `Drag And Drop By Offset` | myElem | 50 | -35 | # Move myElem 50px right and 35px down |
"""
element = self.find_element(locator)
# _unwrap_eventfiring_element can be removed when minimum required Selenium is 4.0 or greater.
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.drag_and_drop_by_offset(element, xoffset, yoffset)
action.perform()
mouse_down/out
def mouse_down(self, locator: Union[WebElement, str]):
self.info(f"Simulating Mouse Down on element '{locator}'.")
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.click_and_hold(element).perform()
mouse_out
def mouse_out(self, locator: Union[WebElement, str]):
self.info(f"Simulating Mouse Out on element '{locator}'.")
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
size = element.size
offsetx = (size["width"] / 2) + 1
offsety = (size["height"] / 2) + 1
action = ActionChains(self.driver)
action.move_to_element(element)
action.move_by_offset(offsetx, offsety)
action.perform()
mouse_over
def mouse_over(self, locator: Union[WebElement, str]):
self.info(f"Simulating Mouse Over on element '{locator}'.")
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.move_to_element(element).perform()
mouse_up
def mouse_up(self, locator: Union[WebElement, str]):
self.info(f"Simulating Mouse Up on element '{locator}'.")
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
ActionChains(self.driver).release(element).perform()
open_context_menu
def open_context_menu(self, locator: Union[WebElement, str]):
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.context_click(element).perform()
simulate_event
def simulate_event(self, locator: Union[WebElement, str], event: str):
element = self.find_element(locator)
script = """
element = arguments[0];
eventName = arguments[1];
if (document.createEventObject) { // IE
return element.fireEvent('on' + eventName, document.createEventObject());
}
var evt = document.createEvent("HTMLEvents");
evt.initEvent(eventName, true, true);
return !element.dispatchEvent(evt);
"""
self.driver.execute_script(script, element, event)
press_key
def press_key(self, locator: Union[WebElement, str], key: str):
if key.startswith("\\") and len(key) > 1:
key = self._map_ascii_key_code_to_key(int(key[1:]))
element = self.find_element(locator)
element.send_keys(key)
press_keys
def press_keys(self, locator: Union[WebElement, None, str] = None, *keys: str):
parsed_keys = self._parse_keys(*keys)
if not is_noney(locator):
self.info(f"Sending key(s) {keys} to {locator} element.")
element = self.find_element(locator)
element = _unwrap_eventfiring_element(element)
ActionChains(self.driver).click(element).perform()
else:
self.info(f"Sending key(s) {keys} to page.")
element = None
for parsed_key in parsed_keys:
actions = ActionChains(self.driver)
for key in parsed_key:
if key.special:
self._press_keys_special_keys(actions, element, parsed_key, key)
else:
self._press_keys_normal_keys(actions, key)
self._special_key_up(actions, parsed_key)
actions.perform()
def _press_keys_normal_keys(self, actions, key):
self.info(f"Sending key{plural_or_not(key.converted)} {key.converted}")
actions.send_keys(key.converted)
def _press_keys_special_keys(self, actions, element, parsed_key, key):
if len(parsed_key) == 1 and element:
self.info(f"Pressing special key {key.original} to element.")
actions.send_keys(key.converted)
elif len(parsed_key) == 1 and not element:
self.info(f"Pressing special key {key.original} to browser.")
actions.send_keys(key.converted)
else:
self.info(f"Pressing special key {key.original} down.")
actions.key_down(key.converted)
def _special_key_up(self, actions, parsed_key):
for key in parsed_key:
if key.special:
self.info(f"Releasing special key {key.original}.")
actions.key_up(key.converted)
get_all_links
def get_all_links(self) -> List[str]:
"""Returns a list containing ids of all links found in current page.
If a link has no id, an empty string will be in the list instead.
"""
links = self.find_elements("tag=a")
return [link.get_attribute("id") for link in links]
mouse_down_on_link
def mouse_down_on_link(self, locator: Union[WebElement, str]):
element = self.find_element(locator, tag="link")
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.click_and_hold(element).perform()
page_should_contain_link
def page_should_contain_link(
self,
locator: Union[WebElement, str],
message: Optional[str] = None,
loglevel: str = "TRACE",
):
self.assert_page_contains(locator, "link", message, loglevel)
page_should_not_contain_link
def page_should_not_contain_link(
self,
locator: Union[WebElement, str],
message: Optional[str] = None,
loglevel: str = "TRACE",
):
self.assert_page_not_contains(locator, "link", message, loglevel)
mouse_down_on_image
def mouse_down_on_image(self, locator: Union[WebElement, str]):
element = self.find_element(locator, tag="image")
# _unwrap_eventfiring_element can be removed when minimum required Selenium is 4.0 or greater.
element = _unwrap_eventfiring_element(element)
action = ActionChains(self.driver)
action.click_and_hold(element).perform()
page_should_contain_image
def page_should_contain_image(
self,
locator: Union[WebElement, str],
message: Optional[str] = None,
loglevel: str = "TRACE",
):
self.assert_page_contains(locator, "image", message, loglevel)
page_should_not_contain_image
def page_should_not_contain_image(
self,
locator: Union[WebElement, str],
message: Optional[str] = None,
loglevel: str = "TRACE",
):
self.assert_page_not_contains(locator, "image", message, loglevel)
get_element_count
def get_element_count(self, locator: Union[WebElement, str]) -> int:
return len(self.find_elements(locator))
some_private_funcations
def _map_ascii_key_code_to_key(self, key_code):
map = {
0: Keys.NULL,
8: Keys.BACK_SPACE,
9: Keys.TAB,
10: Keys.RETURN,
13: Keys.ENTER,
24: Keys.CANCEL,
27: Keys.ESCAPE,
32: Keys.SPACE,
42: Keys.MULTIPLY,
43: Keys.ADD,
44: Keys.SEPARATOR,
45: Keys.SUBTRACT,
56: Keys.DECIMAL,
57: Keys.DIVIDE,
59: Keys.SEMICOLON,
61: Keys.EQUALS,
127: Keys.DELETE,
}
key = map.get(key_code)
if key is None:
key = chr(key_code)
return key
def _map_named_key_code_to_special_key(self, key_name):
try:
return getattr(Keys, key_name)
except AttributeError:
message = f"Unknown key named '{key_name}'."
self.debug(message)
raise ValueError(message)
def _page_contains(self, text):
self.driver.switch_to.default_content()
if self.is_text_present(text):
return True
subframes = self.find_elements("xpath://frame|//iframe")
self.debug(f"Current frame has {len(subframes)} subframes.")
for frame in subframes:
self.driver.switch_to.frame(frame)
found_text = self.is_text_present(text)
self.driver.switch_to.default_content()
if found_text:
return True
return False
def parse_modifier(self, modifier):
modifier = modifier.upper()
modifiers = modifier.split("+")
keys = []
for item in modifiers:
item = item.strip()
item = self._parse_aliases(item)
if hasattr(Keys, item):
keys.append(getattr(Keys, item))
else:
raise ValueError(f"'{item}' modifier does not match to Selenium Keys")
return keys
def _parse_keys(self, *keys):
if not keys:
raise AssertionError('"keys" argument can not be empty.')
list_keys = []
for key in keys:
separate_keys = self._separate_key(key)
separate_keys = self._convert_special_keys(separate_keys)
list_keys.append(separate_keys)
return list_keys
def _parse_aliases(self, key):
if key == "CTRL":
return "CONTROL"
if key == "ESC":
return "ESCAPE"
return key
def _separate_key(self, key):
one_key = ""
list_keys = []
for char in key:
if char == "+" and one_key != "":
list_keys.append(one_key)
one_key = ""
else:
one_key += char
if one_key:
list_keys.append(one_key)
return list_keys
def _convert_special_keys(self, keys):
KeysRecord = namedtuple("KeysRecord", "converted, original special")
converted_keys = []
for key in keys:
key = self._parse_aliases(key)
if self._selenium_keys_has_attr(key):
converted_keys.append(KeysRecord(getattr(Keys, key), key, True))
else:
converted_keys.append(KeysRecord(key, key, False))
return converted_keys
def _selenium_keys_has_attr(self, key):
return hasattr(Keys, key)