playwright_tests/core/basepage.py (174 lines of code) (raw):
import random
from typing import Union
from playwright.sync_api import Page, ElementHandle, Locator
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
class BasePage:
def __init__(self, page: Page):
self.page = page
def _get_element_locator(self, xpath: str, with_wait=True) -> Locator:
"""
This helper function returns the element locator from a given xpath.
"""
if with_wait:
self.wait_for_dom_to_load()
return self.page.locator(xpath)
def _get_elements_locators(self, xpath: str) -> list[Locator]:
"""
This helper function returns a list of element locators from a given xpath.
"""
self.wait_for_dom_to_load()
return self.page.locator(xpath).all()
def _get_current_page_url(self) -> str:
"""
This helper function returns the current page URL.
"""
return self.page.url
def _get_element_handles(self, locator: Locator) -> list[ElementHandle]:
"""
This helper function returns a list of element handles from a given locator.
"""
self.wait_for_dom_to_load()
return locator.element_handles()
def _get_element_handle(self, locator: Locator) -> ElementHandle:
"""
This helper function returns a single element handle from a given locator.
"""
self.wait_for_dom_to_load()
return locator.element_handle()
def _get_text_of_elements(self, locator: Locator) -> list[str]:
"""
This helper function returns a list containing the inner texts of a given locator.
"""
self.wait_for_dom_to_load()
return locator.all_inner_texts()
def _get_text_of_element(self, locator: Locator) -> str:
"""
This helper function returns the inner text of a given locator.
"""
self.wait_for_dom_to_load()
return locator.inner_text()
def _get_text_of_locator(self, locator: Locator) -> str:
"""
This helper function returns the inner text of a given locator.
"""
return locator.inner_text()
def _is_element_empty(self, locator: Locator) -> bool:
"""
This helper function returns checks if the given locator has an inner text.
"""
self.wait_for_dom_to_load()
return not locator.inner_text()
def _get_elements_count(self, locator: Locator) -> int:
"""
This helper function returns the web element count from a given locator.
"""
self.wait_for_dom_to_load()
return locator.count()
def _get_element_attribute_value(self, element: Union[str, Locator, list[Locator],
ElementHandle], attribute: str) -> Union[str, list[str]]:
"""
This helper function returns the given attribute of a given locator or web element.
"""
if isinstance(element, str):
return self._get_element_locator(element).get_attribute(attribute)
elif isinstance(element, list):
self.wait_for_dom_to_load()
values = []
for element in element:
values.append(element.get_attribute(attribute))
return values
else:
self.wait_for_dom_to_load()
return element.get_attribute(attribute)
def _wait_for_given_timeout(self, timeout: float):
"""
This helper function pauses the execution for a given timeout.
"""
self.page.wait_for_timeout(timeout)
def _get_element_input_value(self, locator: Locator) -> str:
"""
This helper function returns the input value of a given element locator.
"""
return locator.input_value()
def _get_element_inner_text_from_page(self, locator: Locator) -> str:
"""
This helper function returns the inner text of a given locator via the page instance.
"""
return locator.inner_text()
def _get_element_text_content(self, locator: Locator) -> str:
"""
This helper function returns the text content of a given locator via the page instance.
"""
return locator.text_content()
def _get_text_content_of_all_locators(self, locator: Locator) -> list[str]:
"""
This helper function returns a list of text content for the given locator.
"""
return locator.all_text_contents()
def _checkbox_interaction(self, element: [str, ElementHandle], check: bool, retries=3,
delay=2000):
"""
This helper function interacts with a checkbox element.
Args:
element (Union[str, ElementHandle]): The element locator to interact with.
check (bool): Whether to check or uncheck the checkbox.
"""
self.wait_for_networkidle()
for attempt in range(retries):
try:
locator = self._get_element_locator(element) if isinstance(
element,str) else element
if check:
locator.check()
else:
locator.uncheck()
break
except (PlaywrightTimeoutError, Exception) as e:
print(f"Checkbox interaction failed. Retrying... {e}")
if attempt < retries - 1:
self.page.wait_for_timeout(delay)
else:
raise Exception("Max retries exceeded. Could not interact with the checkbox")
def _click(self, element: Union[str, Locator, ElementHandle], expected_locator=None,
expected_url=None, with_force=False, retries=3, delay=2000):
"""
This helper function clicks on a given element locator.
Args:
element (Union[str, Locator, ElementHandle]): The element locator to click on.
expected_locator (str): The expected locator to wait for after the click.
expected_url (str): The expected URL to wait for after the click.
with_force (bool): Whether to force the click.
"""
self.wait_for_networkidle()
for attempt in range(retries):
try:
element_locator = self._get_element_locator(element) if isinstance(
element, str) else element
element_locator.click(force=with_force)
if expected_locator:
self._wait_for_locator(expected_locator, timeout=3000)
if expected_url:
self.page.wait_for_url(expected_url, timeout=3000)
break
except PlaywrightTimeoutError:
if expected_locator:
print(f"Expected locator {expected_locator} not found. Retrying...")
if expected_url:
print(f"Expected URL {expected_url} not found. Retrying...")
if attempt < retries - 1:
self.page.wait_for_timeout(delay)
def _click_on_an_element_by_index(self, locator: Locator, index: int):
"""
This helper function clicks on a given element locator based on a given index.
"""
self.wait_for_networkidle()
locator.nth(index).click()
def _click_on_first_item(self, locator: Locator):
"""
This helper function clicks on the first item from a given web element locator list.
"""
self.wait_for_networkidle()
locator.first.click()
def _fill(self, locator: Locator, text: str, with_force=False):
"""
This helper function fills a given text inside a given element locator.
"""
self.wait_for_dom_to_load()
locator.fill(text, force=with_force)
def _type(self, locator: Locator, text: str, delay: int):
"""
This helper function types a given string inside a given element locator with a given delay
"""
self.wait_for_dom_to_load()
locator.type(text=text, delay=delay)
def _press_a_key(self, locator: Locator, key: str):
"""
This helper function types a given key inside a given element locator.
"""
self.wait_for_dom_to_load()
locator.press(key)
def _clear_field(self, locator: Locator):
"""
This helper function clears the given element locator input field.
"""
self.wait_for_dom_to_load()
locator.clear()
def _select_option_by_label(self, locator: Locator, label_name: str):
"""
This helper function selects an element from a given select box based on label.
"""
self.wait_for_dom_to_load()
locator.select_option(label=label_name)
def _select_option_by_value(self, locator: Locator, value: str):
"""
This helper function selects a element from a given select box based on value.
"""
self.wait_for_dom_to_load()
locator.select_option(value=value)
def _select_random_option_by_value(self, dropdown_locator: Locator, locator_options: Locator):
"""
This helper function selects a random option from a given web element locator.
"""
self.wait_for_dom_to_load()
elements = []
for element in locator_options.all():
locator_value = self._get_element_attribute_value(element, 'value')
if locator_value == '':
continue
else:
elements.append(locator_value)
self._select_option_by_value(dropdown_locator, random.choice(elements))
def _accept_dialog(self):
"""
This helper function accepts the displayed dialog.
"""
self.page.on("dialog", lambda dialog: dialog.accept())
def _hover_over_element(self, locator: Locator):
"""
This helper function performs a mouse-over action over a given element locator.
"""
self.wait_for_dom_to_load()
locator.hover()
def _is_element_visible(self, locator: Locator) -> bool:
"""
This helper function finds the locator of the given locator and checks if it is visible.
"""
self.wait_for_dom_to_load()
if locator.count() > 0:
return locator.is_visible()
else:
return False
def _is_locator_visible(self, locator: Locator) -> bool:
"""
This helper function checks if the given locator is visible.
"""
return locator.is_visible()
def _is_checkbox_checked(self, locator: Locator) -> bool:
"""
This helper function checks if a given element locator is checked.
"""
self.wait_for_dom_to_load()
return locator.is_checked()
def _wait_for_locator(self, locator: Locator, timeout=3500):
"""
This helper function waits for a given element locator to be visible based on a given
timeout.
"""
try:
locator.wait_for(state="visible", timeout=timeout)
except PlaywrightTimeoutError:
print(f"{locator} is not displayed")
def _move_mouse_to_location(self, x: int, y: int):
"""
This helper function moves the mouse to a given location.
Args:
x (int): The x-coordinate.
y (int): The y-coordinate.
"""
self.page.mouse.move(x, y)
def wait_for_page_to_load(self):
"""
This helper function awaits for the load event to be fired.
"""
try:
self.page.wait_for_load_state("load")
except PlaywrightTimeoutError:
print("Load event was not fired. Continuing...")
def eval_on_selector_for_last_child_text(self, element: str) -> str:
"""
This helper function evaluates a JavaScript expression on the given element and returns
the text content of the last child element.
"""
return self.page.eval_on_selector(
element,
"el => el.lastChild?.textContent?.trim()"
)
def wait_for_dom_to_load(self):
"""
This helper function awaits for the DOMContentLoaded event to be fired.
"""
try:
self.page.wait_for_load_state("domcontentloaded")
except PlaywrightTimeoutError:
print("DOMContentLoaded event was not fired. Continuing...")
def wait_for_networkidle(self):
"""
This helper function waits until there are no network connections for at least 500ms.
"""
try:
self.page.wait_for_load_state("networkidle")
except PlaywrightTimeoutError:
print("Network idle state was not reached. Continuing...")