Skip to content

Commit 64ee8fc

Browse files
committed
Add click_with_offset() method
1 parent 0985608 commit 64ee8fc

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

help_docs/method_summary.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ self.click_if_visible(selector, by=By.CSS_SELECTOR)
130130

131131
self.click_active_element()
132132

133+
self.click_with_offset(selector, x, y, by=By.CSS_SELECTOR, mark=False, timeout=None)
134+
133135
self.is_selected(selector, by=By.CSS_SELECTOR, timeout=None)
134136
# Duplicates: self.is_checked(selector, by=By.CSS_SELECTOR, timeout=None)
135137

seleniumbase/fixtures/base_case.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,69 @@ def click_active_element(self):
17331733
elif self.slow_mode:
17341734
self.__slow_mode_pause_if_active()
17351735

1736+
def click_with_offset(
1737+
self, selector, x, y, by=By.CSS_SELECTOR, mark=False, timeout=None
1738+
):
1739+
"""
1740+
Click an element at an {X,Y}-offset location.
1741+
{0,0} is the top-left corner of the element.
1742+
If mark==True, will draw a dot at location. (Useful for debugging)
1743+
"""
1744+
from selenium.webdriver.common.action_chains import ActionChains
1745+
1746+
self.__check_scope()
1747+
if not timeout:
1748+
timeout = settings.SMALL_TIMEOUT
1749+
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1750+
timeout = self.__get_new_timeout(timeout)
1751+
selector, by = self.__recalculate_selector(selector, by)
1752+
element = page_actions.wait_for_element_visible(
1753+
self.driver, selector, by, timeout
1754+
)
1755+
self.__demo_mode_highlight_if_active(selector, by)
1756+
if mark:
1757+
selector = self.convert_to_css_selector(selector, by=by)
1758+
selector = re.escape(selector)
1759+
selector = self.__escape_quotes_if_needed(selector)
1760+
px = x - 2
1761+
if px < 0:
1762+
px = 0
1763+
py = y - 2
1764+
if py < 0:
1765+
py = 0
1766+
script = (
1767+
"var canvas = document.querySelector('%s');"
1768+
"var ctx = canvas.getContext('2d');"
1769+
"ctx.fillStyle = '#F80808';"
1770+
"ctx.fillRect(%s, %s, 5, 5);"
1771+
% (selector, px, py)
1772+
)
1773+
self.execute_script(script)
1774+
try:
1775+
element_location = element.location["y"]
1776+
element_location = element_location - 130 + y
1777+
if element_location < 0:
1778+
element_location = 0
1779+
scroll_script = "window.scrollTo(0, %s);" % element_location
1780+
self.driver.execute_script(scroll_script)
1781+
self.sleep(0.1)
1782+
except Exception:
1783+
pass
1784+
try:
1785+
action_chains = ActionChains(self.driver)
1786+
action_chains.move_to_element_with_offset(element, x, y)
1787+
action_chains.click().perform()
1788+
except MoveTargetOutOfBoundsException:
1789+
message = (
1790+
"Target coordinates for click are out-of-bounds!\n"
1791+
"The offset must stay inside the target element!"
1792+
)
1793+
raise Exception(message)
1794+
if self.demo_mode:
1795+
self.__demo_mode_pause_if_active()
1796+
elif self.slow_mode:
1797+
self.__slow_mode_pause_if_active()
1798+
17361799
def is_checked(self, selector, by=By.CSS_SELECTOR, timeout=None):
17371800
"""Determines if a checkbox or a radio button element is checked.
17381801
Returns True if the element is checked.

0 commit comments

Comments
 (0)