Skip to content

More JS. Less jQuery. #1403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta property="og:image" content="https://seleniumbase.io/cdn/img/mac_sb_logo_5.png" />
<link rel="icon" href="https://seleniumbase.io/img/green_logo2.png" />

<p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.io/cdn/img/sb_logo_gs7.png" alt="SeleniumBase" title="SeleniumBase" width="275" /></a></p>
<p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.io/cdn/img/sb_logo_gs8.png" alt="SeleniumBase" title="SeleniumBase" width="275" /></a></p>
<p align="center"><b>Powerful end-to-end testing with <a href="https://www.selenium.dev/documentation/">Selenium</a>, <a href="https://www.python.org/about/">Python</a>, and <a href="https://docs.pytest.org/en/latest/how-to/usage.html">pytest</a>.</b></p>

<p align="center"><a href="https://pypi.python.org/pypi/seleniumbase" target="_blank"><img src="https://img.shields.io/pypi/v/seleniumbase.svg?color=3399EE" alt="PyPI version" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/releases" target="_blank"><img src="https://img.shields.io/github/v/release/seleniumbase/SeleniumBase.svg?color=22AAEE" alt="GitHub version" /></a> <a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/actions" target="_blank"><img src="https://github.com/seleniumbase/SeleniumBase/workflows/CI%20build/badge.svg" alt="SeleniumBase GitHub Actions" /></a> <a href="https://gitter.im/seleniumbase/SeleniumBase" target="_blank"><img src="https://badges.gitter.im/seleniumbase/SeleniumBase.svg" alt="SeleniumBase" /></a></p>
Expand Down
2 changes: 1 addition & 1 deletion help_docs/method_summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ self.hover_and_double_click(

self.drag_and_drop(drag_selector, drop_selector,
drag_by="css selector", drop_by="css selector",
timeout=None)
timeout=None, jquery=False)

self.drag_and_drop_with_offset(
selector, x, y, by="css selector", timeout=None)
Expand Down
2 changes: 1 addition & 1 deletion mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# mkdocs dependencies for generating the seleniumbase.io website
# Minimum Python version: 3.7

regex>=2022.6.2
regex>=2022.7.9
tqdm>=4.64.0
docutils==0.19
python-dateutil==2.8.2
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Pillow==9.2.0;python_version>="3.7"
typing-extensions==3.10.0.2;python_version<"3.6"
typing-extensions==4.1.1;python_version>="3.6" and python_version<"3.7"
typing-extensions==4.2.0;python_version>="3.7" and python_version<"3.9"
rich==12.4.4;python_version>="3.6" and python_version<"4.0"
rich==12.5.1;python_version>="3.6" and python_version<"4.0"
tornado==5.1.1;python_version<"3.5"
tornado==6.1;python_version>="3.5" and python_version<"3.7"
tornado==6.2;python_version>="3.7"
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "3.4.0"
__version__ = "3.4.1"
24 changes: 18 additions & 6 deletions seleniumbase/console_scripts/sb_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ def requests_get(url):
return response


def requests_get_with_retry(url):
response = None
try:
response = requests.get(url)
except Exception:
import time

time.sleep(0.75)
response = requests.get(url)
return response


def main(override=None):
if override:
if override == "chromedriver":
Expand Down Expand Up @@ -344,7 +356,7 @@ def main(override=None):
else:
invalid_run_command()
if get_latest:
url_request = requests.get(last)
url_request = requests_get_with_retry(last)
if url_request.ok:
use_version = url_request.text.split("\r")[0].split("\n")[0]
use_version = use_version.split(".")[0]
Expand All @@ -370,15 +382,15 @@ def main(override=None):
if use_version.isdigit():
edgedriver_st = "https://msedgedriver.azureedge.net/LATEST_RELEASE"
use_version = "%s_%s_%s" % (edgedriver_st, use_version, suffix)
url_request = requests.get(use_version)
url_request = requests_get_with_retry(use_version)
if url_request.ok:
use_version = url_request.text.split("\r")[0].split("\n")[0]
download_url = "https://msedgedriver.azureedge.net/%s/%s" % (
use_version,
file_name,
)
if not get_latest and not use_version == DEFAULT_EDGEDRIVER_VERSION:
url_request = requests.get(download_url)
url_request = requests_get_with_retry(download_url)
if not url_request.ok:
raise Exception(
"Could not find version [%s] of EdgeDriver!" % use_version
Expand Down Expand Up @@ -410,7 +422,7 @@ def main(override=None):
"releases/download/"
"%s/%s" % (headless_ie_version, headless_ie_file_name)
)
url_request = requests.get(headless_ie_url)
url_request = requests_get_with_retry(headless_ie_url)
if url_request.ok:
headless_ie_exists = True
msg = c2 + "HeadlessIEDriver version for download" + cr
Expand Down Expand Up @@ -497,7 +509,7 @@ def main(override=None):
"\nDownloading %s from:\n%s ..."
% (headless_ie_file_name, headless_ie_url)
)
remote_file = requests.get(headless_ie_url)
remote_file = requests_get_with_retry(headless_ie_url)
with open(headless_ie_file_path, "wb") as file:
file.write(remote_file.content)
print("Download Complete!\n")
Expand Down Expand Up @@ -572,7 +584,7 @@ def main(override=None):
print("%s[%s] is now ready for use!%s" % (c1, driver_file, cr))

print("\nDownloading %s from:\n%s ..." % (file_name, download_url))
remote_file = requests.get(download_url)
remote_file = requests_get_with_retry(download_url)
with open(file_path, "wb") as file:
file.write(remote_file.content)
print("Download Complete!\n")
Expand Down
27 changes: 17 additions & 10 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,7 @@ def drag_and_drop(
drag_by="css selector",
drop_by="css selector",
timeout=None,
jquery=False,
):
"""Drag and drop an element from one selector to another."""
self.__check_scope()
Expand All @@ -2292,22 +2293,28 @@ def drag_and_drop(
drag_selector, by=drag_by, timeout=timeout
)
self.__demo_mode_highlight_if_active(drag_selector, drag_by)
self.wait_for_element_visible(
drop_element = self.wait_for_element_visible(
drop_selector, by=drop_by, timeout=timeout
)
self.__demo_mode_highlight_if_active(drop_selector, drop_by)
self.scroll_to(drag_selector, by=drag_by)
drag_selector = self.convert_to_css_selector(drag_selector, drag_by)
drop_selector = self.convert_to_css_selector(drop_selector, drop_by)
drag_and_drop_script = js_utils.get_drag_and_drop_script()
self.safe_execute_script(
drag_and_drop_script
+ (
"$('%s').simulateDragDrop("
"{dropTarget: "
"'%s'});" % (drag_selector, drop_selector)
if not jquery:
drag_and_drop_script = js_utils.get_js_drag_and_drop_script()
self.execute_script(
drag_and_drop_script, drag_element, drop_element, 0, 0, 1, None
)
else:
drag_and_drop_script = js_utils.get_drag_and_drop_script()
self.safe_execute_script(
drag_and_drop_script
+ (
"$('%s').simulateDragDrop("
"{dropTarget: "
"'%s'});" % (drag_selector, drop_selector)
)
)
)
if self.demo_mode:
self.__demo_mode_pause_if_active()
elif self.slow_mode:
Expand All @@ -2332,7 +2339,7 @@ def drag_and_drop_with_offset(
script = js_utils.get_drag_and_drop_with_offset_script(
css_selector, x, y
)
self.safe_execute_script(script)
self.execute_script(script)
if self.demo_mode:
self.__demo_mode_pause_if_active()
elif self.slow_mode:
Expand Down
69 changes: 59 additions & 10 deletions seleniumbase/fixtures/js_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,10 @@ def raise_unable_to_load_jquery_exception(driver):


def activate_jquery(driver):
"""If "jQuery is not defined", use this method to activate it for use.
This happens because jQuery is not always defined on web sites."""
"""
If "jQuery is not defined" on a website, use this method to activate it.
This method is needed because jQuery is not always defined on web sites.
"""
try:
# Let's first find out if jQuery is already defined.
driver.execute_script("jQuery('html');")
Expand All @@ -163,20 +165,15 @@ def activate_jquery(driver):
pass
jquery_js = constants.JQuery.MIN_JS
add_js_link(driver, jquery_js)
for x in range(25):
for x in range(27):
# jQuery needs a small amount of time to activate.
try:
driver.execute_script("jQuery('html');")
return
except Exception:
if x == 15:
add_js_link(driver, jquery_js)
time.sleep(0.1)
try:
add_js_link(driver, jquery_js)
time.sleep(0.5)
driver.execute_script("jQuery('head');")
return
except Exception:
pass
# Since jQuery still isn't activating, give up and raise an exception
raise_unable_to_load_jquery_exception(driver)

Expand Down Expand Up @@ -1021,6 +1018,8 @@ def slow_scroll_to_element(driver, element, browser):


def get_drag_and_drop_script():
# This script uses jQuery to perform a Drag-and-Drop action.
# (Requires the Drag-selector and the Drop-selector to work)
script = r"""(function( $ ) {
$.fn.simulateDragDrop = function(options) {
return this.each(function() {
Expand Down Expand Up @@ -1078,7 +1077,57 @@ def get_drag_and_drop_script():
return script


def get_js_drag_and_drop_script():
# HTML5 Drag-and-Drop script (Requires extra parameters to work)
# param1 (WebElement): Source element to drag
# param2 (WebElement): Target element for the drop (Optional)
# param3 (int): Optional - Drop offset x relative to the target
# param4 (int): Optional - Drop offset y relative to the target
# param4 (int): Optional - Delay in milliseconds (default = 1ms)
# param5 (string): Optional - Key pressed (ALT or CTRL or SHIFT)
script = """var t=arguments,e=t[0],n=t[1],i=t[2]||0,o=t[3]||0,r=t[4]||1,
a=t[5]||'',s='alt'===a||'\ue00a'===a,l='ctrl'===a||'\ue009'===a,
c='shift'===a||'\ue008'===a,u=e.ownerDocument,
f=e.getBoundingClientRect(),g=n?n.getBoundingClientRect():f,
p=f.left+f.width/2,d=f.top+f.height/2,h=g.left+(i||g.width/2),
m=g.top+(o||g.height/2),v=u.elementFromPoint(p,d),
y=u.elementFromPoint(h,m);if(!v||!y){
var E=new Error('source or target element is not interactable');
throw E.code=15,E}var _={constructor:DataTransfer,effectAllowed:null,
dropEffect:null,types:[],files:Object.setPrototypeOf([],null),
_items:Object.setPrototypeOf([],{add:function(t,e){
this[this.length]={_data:''+t,kind:'string',
type:e,getAsFile:function(){},getAsString:function(t){t(this._data)}},
_.types.push(e)},remove:function(t){
Array.prototype.splice.call(this,65535&t,1),_.types.splice(65535&t,1)},
clear:function(t,e){this.length=0,_.types.length=0}}),
setData:function(t,e){this.clearData(t),this._items.add(e,t)},
getData:function(t){for(var e=this._items.length;
e--&&this._items[e].type!==t;);return e>=0?this._items[e]._data:null},
clearData:function(t){for(var e=this._items.length;
e--&&this._items[e].type!==t;);this._items.remove(e)},
setDragImage:function(t){}};function w(t,e,n,i){
for(var o=0;o<e.length;++o){var r=u.createEvent('MouseEvent');
r.initMouseEvent(e[o],!0,!0,u.defaultView,0,0,0,p,d,l,s,c,!1,0,null),
t.dispatchEvent(r)}i&&setTimeout(i,n)}function D(t,e,n,i){
var o=u.createEvent('DragEvent');o.initMouseEvent(
e,!0,!0,u.defaultView,0,0,0,p,d,l,s,c,!1,0,null),Object.setPrototypeOf(
o,null),o.dataTransfer=_,Object.setPrototypeOf(o,DragEvent.prototype),
t.dispatchEvent(o),i&&setTimeout(i,n)}
'items'in DataTransfer.prototype&&(_.items=_._items),
w(v,['pointerdown','mousedown'],1,function(){
for(var t=v;t&&!t.draggable;)t=t.parentElement;if(t&&t.contains(v)){
var e=y.getBoundingClientRect();D(v,'dragstart',r,function(){
var t=y.getBoundingClientRect();p=t.left+h-e.left,d=t.top+m-e.top,D(
y,'dragenter',1,function(){D(y,'dragover',r,
function(){D(u.elementFromPoint(p,d),'drop',1,function(){D(v,'dragend',
1,function(){w(u.elementFromPoint(p,d),
['mouseup','pointerup'])})})})})})}})"""
return script


def get_drag_and_drop_with_offset_script(selector, x, y):
# This script uses pure JS (No jQuery)
script_a = """
var source = document.querySelector("%s");
var offsetX = %f;
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
'typing-extensions==3.10.0.2;python_version<"3.6"', # <3.9 for "rich"
'typing-extensions==4.1.1;python_version>="3.6" and python_version<"3.7"', # noqa: E501
'typing-extensions==4.2.0;python_version>="3.7" and python_version<"3.9"', # noqa: E501
'rich==12.4.4;python_version>="3.6" and python_version<"4.0"',
'rich==12.5.1;python_version>="3.6" and python_version<"4.0"',
'tornado==5.1.1;python_version<"3.5"',
'tornado==6.1;python_version>="3.5" and python_version<"3.7"',
'tornado==6.2;python_version>="3.7"',
Expand Down