Skip to content

Commit 1321343

Browse files
committed
Reduce jQuery use when/where possible
1 parent 8f740df commit 1321343

File tree

1 file changed

+147
-40
lines changed

1 file changed

+147
-40
lines changed

seleniumbase/fixtures/base_case.py

Lines changed: 147 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -719,9 +719,12 @@ def double_click(self, selector, by="css selector", timeout=None):
719719
self.execute_script(double_click_script)
720720
else:
721721
double_click_script = (
722-
"""jQuery('%s').dblclick();""" % css_selector
722+
"""var targetElement1 = arguments[0];
723+
var clickEvent1 = document.createEvent('MouseEvents');
724+
clickEvent1.initEvent('dblclick', true, true);
725+
targetElement1.dispatchEvent(clickEvent1);"""
723726
)
724-
self.safe_execute_script(double_click_script)
727+
self.execute_script(double_click_script, element)
725728
if settings.WAIT_FOR_RSC_ON_CLICKS:
726729
self.wait_for_ready_state_complete()
727730
else:
@@ -797,9 +800,12 @@ def context_click(self, selector, by="css selector", timeout=None):
797800
self.execute_script(right_click_script)
798801
else:
799802
right_click_script = (
800-
"""jQuery('%s').contextmenu();""" % css_selector
803+
"""var targetElement1 = arguments[0];
804+
var clickEvent1 = document.createEvent('MouseEvents');
805+
clickEvent1.initEvent('contextmenu', true, true);
806+
targetElement1.dispatchEvent(clickEvent1);"""
801807
)
802-
self.safe_execute_script(right_click_script)
808+
self.execute_script(right_click_script, element)
803809
if settings.WAIT_FOR_RSC_ON_CLICKS:
804810
self.wait_for_ready_state_complete()
805811
else:
@@ -1971,25 +1977,28 @@ def get_property_value(
19711977
timeout = self.__get_new_timeout(timeout)
19721978
selector, by = self.__recalculate_selector(selector, by)
19731979
self.wait_for_ready_state_complete()
1974-
page_actions.wait_for_element_present(
1980+
element = page_actions.wait_for_element_present(
19751981
self.driver, selector, by, timeout
19761982
)
19771983
try:
19781984
selector = self.convert_to_css_selector(selector, by=by)
19791985
except Exception:
1980-
# Don't run action if can't convert to CSS_Selector for JavaScript
1981-
raise Exception(
1982-
"Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!"
1983-
% (selector, by)
1986+
# If can't convert to CSS_Selector for JS, use element directly
1987+
script = (
1988+
"""var $elm = arguments[0];
1989+
$val = window.getComputedStyle($elm).getPropertyValue('%s');
1990+
return $val;""" % property
19841991
)
1992+
value = self.execute_script(script, element)
1993+
if value is not None:
1994+
return value
1995+
else:
1996+
return ""
19851997
selector = re.escape(selector)
19861998
selector = self.__escape_quotes_if_needed(selector)
19871999
script = """var $elm = document.querySelector('%s');
19882000
$val = window.getComputedStyle($elm).getPropertyValue('%s');
1989-
return $val;""" % (
1990-
selector,
1991-
property,
1992-
)
2001+
return $val;""" % (selector, property)
19932002
value = self.execute_script(script)
19942003
if value is not None:
19952004
return value
@@ -5350,13 +5359,15 @@ def bring_to_front(self, selector, by="css selector"):
53505359
Other element would receive the click: ... }"""
53515360
self.__check_scope()
53525361
selector, by = self.__recalculate_selector(selector, by)
5353-
self.wait_for_element_visible(
5362+
element = self.wait_for_element_visible(
53545363
selector, by=by, timeout=settings.SMALL_TIMEOUT
53555364
)
53565365
try:
53575366
selector = self.convert_to_css_selector(selector, by=by)
53585367
except Exception:
5359-
# Don't run action if can't convert to CSS_Selector for JavaScript
5368+
# If can't convert to CSS_Selector for JS, use element directly
5369+
script = ("""arguments[0].style.zIndex = '999999';""")
5370+
self.execute_script(script, element)
53605371
return
53615372
selector = re.escape(selector)
53625373
selector = self.__escape_quotes_if_needed(selector)
@@ -5425,11 +5436,12 @@ def __highlight(
54255436
selector, by=by, timeout=settings.SMALL_TIMEOUT
54265437
)
54275438
self.__slow_scroll_to_element(element)
5439+
use_element_directly = False
54285440
try:
54295441
selector = self.convert_to_css_selector(selector, by=by)
54305442
except Exception:
5431-
# Don't highlight if can't convert to CSS_SELECTOR
5432-
return
5443+
# If can't convert to CSS_Selector for JS, use element directly
5444+
use_element_directly = True
54335445
if self.highlights:
54345446
loops = self.highlights
54355447
if self.browser == "ie":
@@ -5455,7 +5467,9 @@ def __highlight(
54555467
box_end = style.find(";", box_start) + 1
54565468
original_box_shadow = style[box_start:box_end]
54575469
o_bs = original_box_shadow
5458-
if ":contains" not in selector and ":first" not in selector:
5470+
if use_element_directly:
5471+
self.__highlight_element_with_js(element, loops, o_bs)
5472+
elif ":contains" not in selector and ":first" not in selector:
54595473
selector = re.escape(selector)
54605474
selector = self.__escape_quotes_if_needed(selector)
54615475
self.__highlight_with_js(selector, loops, o_bs)
@@ -5765,9 +5779,8 @@ def js_click(
57655779
if ":contains\\(" not in css_selector:
57665780
self.__js_click(selector, by=by)
57675781
else:
5768-
click_script = """jQuery('%s')[0].click();""" % css_selector
57695782
try:
5770-
self.safe_execute_script(click_script)
5783+
self.__js_click_element(element)
57715784
except Exception:
57725785
self.wait_for_ready_state_complete()
57735786
element = self.wait_for_element_present(
@@ -5777,7 +5790,7 @@ def js_click(
57775790
if self.is_element_clickable(selector):
57785791
self.__element_click(element)
57795792
else:
5780-
self.safe_execute_script(click_script)
5793+
self.__js_click_element(element)
57815794
else:
57825795
if ":contains\\(" not in css_selector:
57835796
self.__js_click_all(selector, by=by)
@@ -5929,14 +5942,23 @@ def jquery_click_all(self, selector, by="css selector", timeout=None):
59295942
def hide_element(self, selector, by="css selector"):
59305943
"""Hide the first element on the page that matches the selector."""
59315944
self.__check_scope()
5945+
element = None
59325946
try:
59335947
self.wait_for_element_visible("body", timeout=1.5)
5934-
self.wait_for_element_present(selector, by=by, timeout=0.5)
5948+
element = self.wait_for_element_present(
5949+
selector, by=by, timeout=0.5
5950+
)
59355951
except Exception:
59365952
pass
59375953
selector, by = self.__recalculate_selector(selector, by)
59385954
css_selector = self.convert_to_css_selector(selector, by=by)
5939-
if ":contains(" in css_selector:
5955+
if ":contains(" in css_selector and element:
5956+
script = (
5957+
'const e = arguments[0];'
5958+
'e.style.display="none";e.style.visibility="hidden";'
5959+
)
5960+
self.execute_script(script, element)
5961+
elif ":contains(" in css_selector and not element:
59405962
selector = self.__make_css_match_first_element_only(css_selector)
59415963
script = """jQuery('%s').hide();""" % selector
59425964
self.safe_execute_script(script)
@@ -5946,7 +5968,8 @@ def hide_element(self, selector, by="css selector"):
59465968
script = (
59475969
'const e = document.querySelector("%s");'
59485970
'e.style.display="none";e.style.visibility="hidden";'
5949-
% css_selector)
5971+
% css_selector
5972+
)
59505973
self.execute_script(script)
59515974

59525975
def hide_elements(self, selector, by="css selector"):
@@ -5977,14 +6000,21 @@ def hide_elements(self, selector, by="css selector"):
59776000
def show_element(self, selector, by="css selector"):
59786001
"""Show the first element on the page that matches the selector."""
59796002
self.__check_scope()
6003+
element = None
59806004
try:
59816005
self.wait_for_element_visible("body", timeout=1.5)
5982-
self.wait_for_element_present(selector, by=by, timeout=1)
6006+
element = self.wait_for_element_present(selector, by=by, timeout=1)
59836007
except Exception:
59846008
pass
59856009
selector, by = self.__recalculate_selector(selector, by)
59866010
css_selector = self.convert_to_css_selector(selector, by=by)
5987-
if ":contains(" in css_selector:
6011+
if ":contains(" in css_selector and element:
6012+
script = (
6013+
'const e = arguments[0];'
6014+
'e.style.display="";e.style.visibility="visible";'
6015+
)
6016+
self.execute_script(script, element)
6017+
elif ":contains(" in css_selector and not element:
59886018
selector = self.__make_css_match_first_element_only(css_selector)
59896019
script = """jQuery('%s').show(0);""" % selector
59906020
self.safe_execute_script(script)
@@ -6026,14 +6056,23 @@ def show_elements(self, selector, by="css selector"):
60266056
def remove_element(self, selector, by="css selector"):
60276057
"""Remove the first element on the page that matches the selector."""
60286058
self.__check_scope()
6059+
element = None
60296060
try:
60306061
self.wait_for_element_visible("body", timeout=1.5)
6031-
self.wait_for_element_present(selector, by=by, timeout=0.5)
6062+
element = self.wait_for_element_present(
6063+
selector, by=by, timeout=0.5
6064+
)
60326065
except Exception:
60336066
pass
60346067
selector, by = self.__recalculate_selector(selector, by)
60356068
css_selector = self.convert_to_css_selector(selector, by=by)
6036-
if ":contains(" in css_selector:
6069+
if ":contains(" in css_selector and element:
6070+
script = (
6071+
'const e = arguments[0];'
6072+
'e.parentElement.removeChild(e);'
6073+
)
6074+
self.execute_script(script, element)
6075+
elif ":contains(" in css_selector and not element:
60376076
selector = self.__make_css_match_first_element_only(css_selector)
60386077
script = """jQuery('%s').remove();""" % selector
60396078
self.safe_execute_script(script)
@@ -7547,8 +7586,11 @@ def set_value(
75477586
)
75487587
self.execute_script(script)
75497588
else:
7550-
script = """jQuery('%s')[0].value='%s';""" % (css_selector, value)
7551-
self.safe_execute_script(script)
7589+
element = self.wait_for_element_present(
7590+
original_selector, by=by, timeout=timeout
7591+
)
7592+
script = """arguments[0].value='%s';""" % value
7593+
self.execute_script(script, element)
75527594
if text.endswith("\n"):
75537595
element = self.wait_for_element_present(
75547596
original_selector, by=by, timeout=timeout
@@ -7568,6 +7610,19 @@ def set_value(
75687610
self.execute_script(mouse_move_script)
75697611
except Exception:
75707612
pass
7613+
elif the_type == "range" and ":contains\\(" in css_selector:
7614+
try:
7615+
element = self.wait_for_element_present(
7616+
original_selector, by=by, timeout=1
7617+
)
7618+
mouse_move_script = (
7619+
"""m_elm = arguments[0];"""
7620+
"""m_evt = new Event('mousemove');"""
7621+
"""m_elm.dispatchEvent(m_evt);"""
7622+
)
7623+
self.execute_script(mouse_move_script, element)
7624+
except Exception:
7625+
pass
75717626
self.__demo_mode_pause_if_active()
75727627

75737628
def js_update_text(self, selector, text, by="css selector", timeout=None):
@@ -7664,11 +7719,8 @@ def set_text_content(
76647719
)
76657720
self.execute_script(script)
76667721
else:
7667-
script = """jQuery('%s')[0].textContent='%s';""" % (
7668-
css_selector,
7669-
value,
7670-
)
7671-
self.safe_execute_script(script)
7722+
script = """arguments[0].textContent='%s';""" % value
7723+
self.execute_script(script, element)
76727724
self.__demo_mode_pause_if_active()
76737725

76747726
def jquery_update_text(
@@ -7759,8 +7811,9 @@ def get_value(self, selector, by="css selector", timeout=None):
77597811
)
77607812
value = self.execute_script(script)
77617813
else:
7762-
script = """return jQuery('%s')[0].value;""" % css_selector
7763-
value = self.safe_execute_script(script)
7814+
element = self.wait_for_element_present(selector, by=by, timeout=1)
7815+
script = """return arguments[0].value;"""
7816+
value = self.execute_script(script, element)
77647817
return value
77657818

77667819
def set_time_limit(self, time_limit):
@@ -12536,6 +12589,40 @@ def __js_click(self, selector, by="css selector"):
1253612589
)
1253712590
self.execute_script(script)
1253812591

12592+
def __js_click_element(self, element):
12593+
"""Clicks an element using pure JS. Does not use jQuery."""
12594+
is_visible = element.is_displayed()
12595+
current_url = self.get_current_url()
12596+
script = (
12597+
"""var simulateClick = function (elem) {
12598+
var evt = new MouseEvent('click', {
12599+
bubbles: true,
12600+
cancelable: true,
12601+
view: window
12602+
});
12603+
var canceled = !elem.dispatchEvent(evt);
12604+
};
12605+
var someLink = arguments[0];
12606+
simulateClick(someLink);"""
12607+
)
12608+
if hasattr(self, "recorder_mode") and self.recorder_mode:
12609+
self.save_recorded_actions()
12610+
try:
12611+
self.execute_script(script, element)
12612+
except Exception:
12613+
# If element was visible but no longer, or on a different page now,
12614+
# assume that the click actually worked and continue with the test.
12615+
if (
12616+
(is_visible and not element.is_displayed())
12617+
or current_url != self.get_current_url()
12618+
):
12619+
return # The click worked, but threw an Exception. Keep going.
12620+
# It appears the first click didn't work. Make another attempt.
12621+
self.wait_for_ready_state_complete()
12622+
# If the regular mouse-simulated click fails, do a basic JS click
12623+
script = ("""arguments[0].click();""")
12624+
self.execute_script(script, element)
12625+
1253912626
def __js_click_all(self, selector, by="css selector"):
1254012627
"""Clicks all matching elements using pure JS. (No jQuery)"""
1254112628
selector, by = self.__recalculate_selector(selector, by)
@@ -12977,6 +13064,10 @@ def __highlight_with_js(self, selector, loops, o_bs):
1297713064
self.wait_for_ready_state_complete()
1297813065
js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
1297913066

13067+
def __highlight_element_with_js(self, element, loops, o_bs):
13068+
self.wait_for_ready_state_complete()
13069+
js_utils.highlight_element_with_js(self.driver, element, loops, o_bs)
13070+
1298013071
def __highlight_with_jquery(self, selector, loops, o_bs):
1298113072
self.wait_for_ready_state_complete()
1298213073
js_utils.highlight_with_jquery(self.driver, selector, loops, o_bs)
@@ -12994,6 +13085,19 @@ def __highlight_with_js_2(self, message, selector, o_bs):
1299413085
self.driver, message, selector, o_bs, duration
1299513086
)
1299613087

13088+
def __highlight_element_with_js_2(self, message, element, o_bs):
13089+
duration = self.message_duration
13090+
if not duration:
13091+
duration = settings.DEFAULT_MESSAGE_DURATION
13092+
if (
13093+
(self.headless or self.headless2 or self.xvfb)
13094+
and float(duration) > 0.75
13095+
):
13096+
duration = 0.75
13097+
js_utils.highlight_element_with_js_2(
13098+
self.driver, message, element, o_bs, duration
13099+
)
13100+
1299713101
def __highlight_with_jquery_2(self, message, selector, o_bs):
1299813102
duration = self.message_duration
1299913103
if not duration:
@@ -13032,11 +13136,12 @@ def __highlight_with_assert_success(
1303213136
selector, by=by, timeout=settings.SMALL_TIMEOUT
1303313137
)
1303413138
self.__slow_scroll_to_element(element)
13139+
use_element_directly = False
1303513140
try:
1303613141
selector = self.convert_to_css_selector(selector, by=by)
1303713142
except Exception:
13038-
# Don't highlight if can't convert to CSS_SELECTOR
13039-
return
13143+
# If can't convert to CSS_Selector for JS, use element directly
13144+
use_element_directly = True
1304013145

1304113146
o_bs = "" # original_box_shadow
1304213147
try:
@@ -13055,7 +13160,9 @@ def __highlight_with_assert_success(
1305513160
original_box_shadow = style[box_start:box_end]
1305613161
o_bs = original_box_shadow
1305713162

13058-
if ":contains" not in selector and ":first" not in selector:
13163+
if use_element_directly:
13164+
self.__highlight_element_with_js_2(message, element, o_bs)
13165+
elif ":contains" not in selector and ":first" not in selector:
1305913166
selector = re.escape(selector)
1306013167
selector = self.__escape_quotes_if_needed(selector)
1306113168
self.__highlight_with_js_2(message, selector, o_bs)

0 commit comments

Comments
 (0)