Merge pull request #219 from seleniumbase/major-refactoring
Major refactoring
This commit is contained in:
commit
ddcf39bcb5
|
@ -5,13 +5,13 @@ selenium==3.14.1
|
||||||
pytest>=3.8.2
|
pytest>=3.8.2
|
||||||
pytest-cov>=2.6.0
|
pytest-cov>=2.6.0
|
||||||
pytest-html>=1.19.0
|
pytest-html>=1.19.0
|
||||||
pytest-rerunfailures>=4.1
|
pytest-rerunfailures>=4.2
|
||||||
pytest-xdist>=1.23.2
|
pytest-xdist>=1.23.2
|
||||||
parameterized==0.6.1
|
parameterized==0.6.1
|
||||||
|
beautifulsoup4>=4.6.0
|
||||||
six>=1.11.0
|
six>=1.11.0
|
||||||
pyotp>=2.2.6
|
pyotp>=2.2.6
|
||||||
requests>=2.19.1
|
requests>=2.19.1
|
||||||
beautifulsoup4>=4.6.3
|
|
||||||
unittest2>=1.1.0
|
unittest2>=1.1.0
|
||||||
chardet>=3.0.4
|
chardet>=3.0.4
|
||||||
urllib3>=1.23
|
urllib3>=1.23
|
||||||
|
|
|
@ -0,0 +1,796 @@
|
||||||
|
"""
|
||||||
|
This module contains methods for running website tours.
|
||||||
|
These helper methods SHOULD NOT be called directly from tests.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from seleniumbase.config import settings
|
||||||
|
from seleniumbase.core import style_sheet
|
||||||
|
from seleniumbase.fixtures import constants
|
||||||
|
from seleniumbase.fixtures import js_utils
|
||||||
|
from seleniumbase.fixtures import page_actions
|
||||||
|
from seleniumbase.fixtures import page_utils
|
||||||
|
|
||||||
|
|
||||||
|
def raise_unable_to_load_jquery_exception(driver):
|
||||||
|
""" The most-likely reason for jQuery not loading on web pages. """
|
||||||
|
raise Exception(
|
||||||
|
'''Unable to load jQuery on "%s" due to a possible violation '''
|
||||||
|
'''of the website's Content Security Policy '''
|
||||||
|
'''directive. ''' % driver.current_url)
|
||||||
|
|
||||||
|
|
||||||
|
def activate_bootstrap(driver):
|
||||||
|
""" Allows you to use Bootstrap Tours with SeleniumBase
|
||||||
|
http://bootstraptour.com/
|
||||||
|
"""
|
||||||
|
bootstrap_tour_css = constants.BootstrapTour.MIN_CSS
|
||||||
|
bootstrap_tour_js = constants.BootstrapTour.MIN_JS
|
||||||
|
|
||||||
|
verify_script = ("""// Verify Bootstrap Tour activated
|
||||||
|
var tour2 = new Tour({
|
||||||
|
});""")
|
||||||
|
|
||||||
|
backdrop_style = style_sheet.bt_backdrop_style
|
||||||
|
js_utils.add_css_style(driver, backdrop_style)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
for x in range(4):
|
||||||
|
js_utils.activate_jquery(driver)
|
||||||
|
js_utils.add_css_link(driver, bootstrap_tour_css)
|
||||||
|
js_utils.add_js_link(driver, bootstrap_tour_js)
|
||||||
|
time.sleep(0.1)
|
||||||
|
for x in range(int(settings.MINI_TIMEOUT * 2.0)):
|
||||||
|
# Bootstrap needs a small amount of time to load & activate.
|
||||||
|
try:
|
||||||
|
driver.execute_script(verify_script)
|
||||||
|
time.sleep(0.05)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.15)
|
||||||
|
raise_unable_to_load_jquery_exception(driver)
|
||||||
|
|
||||||
|
|
||||||
|
def is_bootstrap_activated(driver):
|
||||||
|
verify_script = ("""// Verify Bootstrap Tour activated
|
||||||
|
var tour2 = new Tour({
|
||||||
|
});""")
|
||||||
|
try:
|
||||||
|
driver.execute_script(verify_script)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def activate_hopscotch(driver):
|
||||||
|
""" Allows you to use Hopscotch Tours with SeleniumBase
|
||||||
|
http://linkedin.github.io/hopscotch/
|
||||||
|
"""
|
||||||
|
hopscotch_css = constants.Hopscotch.MIN_CSS
|
||||||
|
hopscotch_js = constants.Hopscotch.MIN_JS
|
||||||
|
backdrop_style = style_sheet.hops_backdrop_style
|
||||||
|
|
||||||
|
verify_script = ("""// Verify Hopscotch activated
|
||||||
|
var hops = hopscotch.isActive;
|
||||||
|
""")
|
||||||
|
|
||||||
|
activate_bootstrap(driver)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
js_utils.add_css_style(driver, backdrop_style)
|
||||||
|
for x in range(4):
|
||||||
|
js_utils.activate_jquery(driver)
|
||||||
|
js_utils.add_css_link(driver, hopscotch_css)
|
||||||
|
js_utils.add_js_link(driver, hopscotch_js)
|
||||||
|
time.sleep(0.1)
|
||||||
|
for x in range(int(settings.MINI_TIMEOUT * 2.0)):
|
||||||
|
# Hopscotch needs a small amount of time to load & activate.
|
||||||
|
try:
|
||||||
|
driver.execute_script(verify_script)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
time.sleep(0.05)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.15)
|
||||||
|
raise_unable_to_load_jquery_exception(driver)
|
||||||
|
|
||||||
|
|
||||||
|
def is_hopscotch_activated(driver):
|
||||||
|
verify_script = ("""// Verify Hopscotch activated
|
||||||
|
var hops = hopscotch.isActive;
|
||||||
|
""")
|
||||||
|
try:
|
||||||
|
driver.execute_script(verify_script)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def activate_introjs(driver):
|
||||||
|
""" Allows you to use IntroJS Tours with SeleniumBase
|
||||||
|
https://introjs.com/
|
||||||
|
"""
|
||||||
|
intro_css = constants.IntroJS.MIN_CSS
|
||||||
|
intro_js = constants.IntroJS.MIN_JS
|
||||||
|
|
||||||
|
verify_script = ("""// Verify IntroJS activated
|
||||||
|
var intro2 = introJs();
|
||||||
|
""")
|
||||||
|
|
||||||
|
activate_bootstrap(driver)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
for x in range(4):
|
||||||
|
js_utils.activate_jquery(driver)
|
||||||
|
js_utils.add_css_link(driver, intro_css)
|
||||||
|
js_utils.add_js_link(driver, intro_js)
|
||||||
|
time.sleep(0.1)
|
||||||
|
for x in range(int(settings.MINI_TIMEOUT * 2.0)):
|
||||||
|
# IntroJS needs a small amount of time to load & activate.
|
||||||
|
try:
|
||||||
|
driver.execute_script(verify_script)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
time.sleep(0.05)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.15)
|
||||||
|
raise_unable_to_load_jquery_exception(driver)
|
||||||
|
|
||||||
|
|
||||||
|
def is_introjs_activated(driver):
|
||||||
|
verify_script = ("""// Verify IntroJS activated
|
||||||
|
var intro2 = introJs();
|
||||||
|
""")
|
||||||
|
try:
|
||||||
|
driver.execute_script(verify_script)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def activate_shepherd(driver):
|
||||||
|
""" Allows you to use Shepherd Tours with SeleniumBase
|
||||||
|
http://github.hubspot.com/shepherd/docs/welcome/
|
||||||
|
"""
|
||||||
|
shepherd_js = constants.Shepherd.MIN_JS
|
||||||
|
sh_theme_arrows_css = constants.Shepherd.THEME_ARROWS_CSS
|
||||||
|
sh_theme_arrows_fix_css = constants.Shepherd.THEME_ARR_FIX_CSS
|
||||||
|
sh_theme_default_css = constants.Shepherd.THEME_DEFAULT_CSS
|
||||||
|
sh_theme_dark_css = constants.Shepherd.THEME_DARK_CSS
|
||||||
|
sh_theme_sq_css = constants.Shepherd.THEME_SQ_CSS
|
||||||
|
sh_theme_sq_dark_css = constants.Shepherd.THEME_SQ_DK_CSS
|
||||||
|
tether_js = constants.Tether.MIN_JS
|
||||||
|
spinner_css = constants.Messenger.SPINNER_CSS
|
||||||
|
sh_style = style_sheet.sh_style_test
|
||||||
|
backdrop_style = style_sheet.sh_backdrop_style
|
||||||
|
|
||||||
|
activate_bootstrap(driver)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
js_utils.add_css_style(driver, backdrop_style)
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
for x in range(4):
|
||||||
|
js_utils.add_css_link(driver, spinner_css)
|
||||||
|
js_utils.add_css_link(driver, sh_theme_arrows_css)
|
||||||
|
js_utils.add_css_link(driver, sh_theme_arrows_fix_css)
|
||||||
|
js_utils.add_css_link(driver, sh_theme_default_css)
|
||||||
|
js_utils.add_css_link(driver, sh_theme_dark_css)
|
||||||
|
js_utils.add_css_link(driver, sh_theme_sq_css)
|
||||||
|
js_utils.add_css_link(driver, sh_theme_sq_dark_css)
|
||||||
|
js_utils.add_js_link(driver, tether_js)
|
||||||
|
js_utils.add_js_link(driver, shepherd_js)
|
||||||
|
time.sleep(0.1)
|
||||||
|
for x in range(int(settings.MINI_TIMEOUT * 2.0)):
|
||||||
|
# Shepherd needs a small amount of time to load & activate.
|
||||||
|
try:
|
||||||
|
driver.execute_script(sh_style) # Verify Shepherd has loaded
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
driver.execute_script(sh_style) # Need it twice for ordering
|
||||||
|
js_utils.wait_for_ready_state_complete(driver)
|
||||||
|
js_utils.wait_for_angularjs(driver)
|
||||||
|
time.sleep(0.05)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.15)
|
||||||
|
raise_unable_to_load_jquery_exception(driver)
|
||||||
|
|
||||||
|
|
||||||
|
def is_shepherd_activated(driver):
|
||||||
|
sh_style = style_sheet.sh_style_test
|
||||||
|
try:
|
||||||
|
driver.execute_script(sh_style) # Verify Shepherd has loaded
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def play_shepherd_tour(driver, tour_steps, msg_dur, name=None, interval=0):
|
||||||
|
""" Plays a Shepherd tour on the current website. """
|
||||||
|
instructions = ""
|
||||||
|
for tour_step in tour_steps[name]:
|
||||||
|
instructions += tour_step
|
||||||
|
instructions += ("""
|
||||||
|
// Start the tour
|
||||||
|
tour.start();
|
||||||
|
$tour = tour;""")
|
||||||
|
autoplay = False
|
||||||
|
if interval and interval > 0:
|
||||||
|
autoplay = True
|
||||||
|
interval = float(interval)
|
||||||
|
if interval < 0.5:
|
||||||
|
interval = 0.5
|
||||||
|
|
||||||
|
if not is_shepherd_activated(driver):
|
||||||
|
activate_shepherd(driver)
|
||||||
|
|
||||||
|
if len(tour_steps[name]) > 1:
|
||||||
|
try:
|
||||||
|
selector = re.search(
|
||||||
|
r"[\S\s]+{element: '([\S\s]+)', on: [\S\s]+",
|
||||||
|
tour_steps[name][1]).group(1)
|
||||||
|
selector = selector.replace('\\', '')
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, selector, by=By.CSS_SELECTOR,
|
||||||
|
timeout=settings.SMALL_TIMEOUT)
|
||||||
|
except Exception:
|
||||||
|
js_utils.post_messenger_error_message(
|
||||||
|
driver, "Tour Error: {'%s'} was not found!" % selector,
|
||||||
|
msg_dur, duration=settings.SMALL_TIMEOUT)
|
||||||
|
raise Exception(
|
||||||
|
"Tour Error: {'%s'} was not found! "
|
||||||
|
"Exiting due to failure on first tour step!"
|
||||||
|
"" % selector)
|
||||||
|
driver.execute_script(instructions)
|
||||||
|
tour_on = True
|
||||||
|
if autoplay:
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
latest_element = None
|
||||||
|
latest_text = None
|
||||||
|
while tour_on:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
result = driver.execute_script(
|
||||||
|
"return Shepherd.activeTour.currentStep.isOpen()")
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
result = None
|
||||||
|
if result:
|
||||||
|
tour_on = True
|
||||||
|
if autoplay:
|
||||||
|
try:
|
||||||
|
element = driver.execute_script(
|
||||||
|
"return Shepherd.activeTour.currentStep"
|
||||||
|
".options.attachTo.element")
|
||||||
|
shep_text = driver.execute_script(
|
||||||
|
"return Shepherd.activeTour.currentStep"
|
||||||
|
".options.text")
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
if element != latest_element or shep_text != latest_text:
|
||||||
|
latest_element = element
|
||||||
|
latest_text = shep_text
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
now_ms = time.time() * 1000.0
|
||||||
|
if now_ms >= stop_ms:
|
||||||
|
if ((element == latest_element) and
|
||||||
|
(shep_text == latest_text)):
|
||||||
|
driver.execute_script("Shepherd.activeTour.next()")
|
||||||
|
try:
|
||||||
|
latest_element = driver.execute_script(
|
||||||
|
"return Shepherd.activeTour.currentStep"
|
||||||
|
".options.attachTo.element")
|
||||||
|
latest_text = driver.execute_script(
|
||||||
|
"return Shepherd.activeTour.currentStep"
|
||||||
|
".options.text")
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
selector = driver.execute_script(
|
||||||
|
"return Shepherd.activeTour"
|
||||||
|
".currentStep.options.attachTo.element")
|
||||||
|
try:
|
||||||
|
js_utils.wait_for_css_query_selector(
|
||||||
|
driver, selector, timeout=settings.SMALL_TIMEOUT)
|
||||||
|
except Exception:
|
||||||
|
remove_script = (
|
||||||
|
"jQuery('%s').remove()" % "div.shepherd-content")
|
||||||
|
driver.execute_script(remove_script)
|
||||||
|
js_utils.post_messenger_error_message(
|
||||||
|
driver, "Tour Error: {'%s'} was not found!" % selector,
|
||||||
|
msg_dur, duration=settings.SMALL_TIMEOUT)
|
||||||
|
time.sleep(0.1)
|
||||||
|
driver.execute_script("Shepherd.activeTour.next()")
|
||||||
|
if autoplay:
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
tour_on = True
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def play_bootstrap_tour(
|
||||||
|
driver, tour_steps, browser, msg_dur, name=None, interval=0):
|
||||||
|
""" Plays a Bootstrap tour on the current website. """
|
||||||
|
instructions = ""
|
||||||
|
for tour_step in tour_steps[name]:
|
||||||
|
instructions += tour_step
|
||||||
|
instructions += (
|
||||||
|
"""]);
|
||||||
|
// Initialize the tour
|
||||||
|
tour.init();
|
||||||
|
// Start the tour
|
||||||
|
tour.start();
|
||||||
|
// Fix timing issue by restarting tour immediately
|
||||||
|
tour.restart();
|
||||||
|
// Save for later
|
||||||
|
$tour = tour;""")
|
||||||
|
|
||||||
|
if interval and interval > 0:
|
||||||
|
if interval < 1:
|
||||||
|
interval = 1
|
||||||
|
interval = str(float(interval) * 1000.0)
|
||||||
|
instructions = instructions.replace(
|
||||||
|
'duration: 0,', 'duration: %s,' % interval)
|
||||||
|
|
||||||
|
if not is_bootstrap_activated(driver):
|
||||||
|
activate_bootstrap(driver)
|
||||||
|
|
||||||
|
if len(tour_steps[name]) > 1:
|
||||||
|
try:
|
||||||
|
if "element: " in tour_steps[name][1]:
|
||||||
|
selector = re.search(
|
||||||
|
r"[\S\s]+element: '([\S\s]+)',[\S\s]+title: '",
|
||||||
|
tour_steps[name][1]).group(1)
|
||||||
|
selector = selector.replace('\\', '').replace(':first', '')
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, selector, by=By.CSS_SELECTOR,
|
||||||
|
timeout=settings.SMALL_TIMEOUT)
|
||||||
|
else:
|
||||||
|
selector = "html"
|
||||||
|
except Exception:
|
||||||
|
js_utils.post_messenger_error_message(
|
||||||
|
driver, "Tour Error: {'%s'} was not found!" % selector,
|
||||||
|
msg_dur, duration=settings.SMALL_TIMEOUT)
|
||||||
|
raise Exception(
|
||||||
|
"Tour Error: {'%s'} was not found! "
|
||||||
|
"Exiting due to failure on first tour step!"
|
||||||
|
"" % selector)
|
||||||
|
|
||||||
|
driver.execute_script(instructions)
|
||||||
|
tour_on = True
|
||||||
|
while tour_on:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
if browser != "firefox":
|
||||||
|
result = driver.execute_script(
|
||||||
|
"return $tour.ended()")
|
||||||
|
else:
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, ".tour-tour", by=By.CSS_SELECTOR, timeout=0.4)
|
||||||
|
result = False
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
result = None
|
||||||
|
if result is False:
|
||||||
|
tour_on = True
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
if browser != "firefox":
|
||||||
|
result = driver.execute_script(
|
||||||
|
"return $tour.ended()")
|
||||||
|
else:
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, ".tour-tour", by=By.CSS_SELECTOR, timeout=0.4)
|
||||||
|
result = False
|
||||||
|
if result is False:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def play_hopscotch_tour(
|
||||||
|
driver, tour_steps, browser, msg_dur, name=None, interval=0):
|
||||||
|
""" Plays a Hopscotch tour on the current website. """
|
||||||
|
instructions = ""
|
||||||
|
for tour_step in tour_steps[name]:
|
||||||
|
instructions += tour_step
|
||||||
|
instructions += (
|
||||||
|
"""]
|
||||||
|
};
|
||||||
|
// Start the tour!
|
||||||
|
hopscotch.startTour(tour);
|
||||||
|
$tour = hopscotch;""")
|
||||||
|
autoplay = False
|
||||||
|
if interval and interval > 0:
|
||||||
|
autoplay = True
|
||||||
|
interval = float(interval)
|
||||||
|
if interval < 0.5:
|
||||||
|
interval = 0.5
|
||||||
|
|
||||||
|
if not is_hopscotch_activated(driver):
|
||||||
|
activate_hopscotch(driver)
|
||||||
|
|
||||||
|
if len(tour_steps[name]) > 1:
|
||||||
|
try:
|
||||||
|
if "target: " in tour_steps[name][1]:
|
||||||
|
selector = re.search(
|
||||||
|
r"[\S\s]+target: '([\S\s]+)',[\S\s]+title: '",
|
||||||
|
tour_steps[name][1]).group(1)
|
||||||
|
selector = selector.replace('\\', '').replace(':first', '')
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, selector, by=By.CSS_SELECTOR,
|
||||||
|
timeout=settings.SMALL_TIMEOUT)
|
||||||
|
else:
|
||||||
|
selector = "html"
|
||||||
|
except Exception:
|
||||||
|
js_utils.post_messenger_error_message(
|
||||||
|
driver, "Tour Error: {'%s'} was not found!" % selector,
|
||||||
|
msg_dur, duration=settings.SMALL_TIMEOUT)
|
||||||
|
raise Exception(
|
||||||
|
"Tour Error: {'%s'} was not found! "
|
||||||
|
"Exiting due to failure on first tour step!"
|
||||||
|
"" % selector)
|
||||||
|
|
||||||
|
driver.execute_script(instructions)
|
||||||
|
tour_on = True
|
||||||
|
if autoplay:
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
latest_step = 0
|
||||||
|
while tour_on:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
if browser != "firefox":
|
||||||
|
result = not driver.execute_script(
|
||||||
|
"return $tour.isActive")
|
||||||
|
else:
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, ".hopscotch-bubble",
|
||||||
|
by=By.CSS_SELECTOR, timeout=0.4)
|
||||||
|
result = False
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
result = None
|
||||||
|
if result is False:
|
||||||
|
tour_on = True
|
||||||
|
if autoplay:
|
||||||
|
try:
|
||||||
|
current_step = driver.execute_script(
|
||||||
|
"return $tour.getCurrStepNum()")
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
if current_step != latest_step:
|
||||||
|
latest_step = current_step
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
now_ms = time.time() * 1000.0
|
||||||
|
if now_ms >= stop_ms:
|
||||||
|
if current_step == latest_step:
|
||||||
|
driver.execute_script("return $tour.nextStep()")
|
||||||
|
try:
|
||||||
|
latest_step = driver.execute_script(
|
||||||
|
"return $tour.getCurrStepNum()")
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
if browser != "firefox":
|
||||||
|
result = not driver.execute_script(
|
||||||
|
"return $tour.isActive")
|
||||||
|
else:
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, ".hopscotch-bubble",
|
||||||
|
by=By.CSS_SELECTOR, timeout=0.4)
|
||||||
|
result = False
|
||||||
|
if result is False:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def play_introjs_tour(
|
||||||
|
driver, tour_steps, browser, msg_dur, name=None, interval=0):
|
||||||
|
""" Plays an IntroJS tour on the current website. """
|
||||||
|
instructions = ""
|
||||||
|
for tour_step in tour_steps[name]:
|
||||||
|
instructions += tour_step
|
||||||
|
instructions += (
|
||||||
|
"""]
|
||||||
|
});
|
||||||
|
intro.setOption("disableInteraction", true);
|
||||||
|
intro.setOption("overlayOpacity", .29);
|
||||||
|
intro.setOption("scrollToElement", true);
|
||||||
|
intro.setOption("keyboardNavigation", true);
|
||||||
|
intro.setOption("exitOnEsc", false);
|
||||||
|
intro.setOption("exitOnOverlayClick", false);
|
||||||
|
intro.setOption("showStepNumbers", false);
|
||||||
|
intro.setOption("showProgress", false);
|
||||||
|
intro.start();
|
||||||
|
$tour = intro;
|
||||||
|
};
|
||||||
|
// Start the tour
|
||||||
|
startIntro();
|
||||||
|
""")
|
||||||
|
autoplay = False
|
||||||
|
if interval and interval > 0:
|
||||||
|
autoplay = True
|
||||||
|
interval = float(interval)
|
||||||
|
if interval < 0.5:
|
||||||
|
interval = 0.5
|
||||||
|
|
||||||
|
if not is_introjs_activated(driver):
|
||||||
|
activate_introjs(driver)
|
||||||
|
|
||||||
|
if len(tour_steps[name]) > 1:
|
||||||
|
try:
|
||||||
|
if "element: " in tour_steps[name][1]:
|
||||||
|
selector = re.search(
|
||||||
|
r"[\S\s]+element: '([\S\s]+)',[\S\s]+intro: '",
|
||||||
|
tour_steps[name][1]).group(1)
|
||||||
|
selector = selector.replace('\\', '')
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, selector, by=By.CSS_SELECTOR,
|
||||||
|
timeout=settings.SMALL_TIMEOUT)
|
||||||
|
else:
|
||||||
|
selector = "html"
|
||||||
|
except Exception:
|
||||||
|
js_utils.post_messenger_error_message(
|
||||||
|
driver, "Tour Error: {'%s'} was not found!" % selector,
|
||||||
|
msg_dur, duration=settings.SMALL_TIMEOUT)
|
||||||
|
raise Exception(
|
||||||
|
"Tour Error: {'%s'} was not found! "
|
||||||
|
"Exiting due to failure on first tour step!"
|
||||||
|
"" % selector)
|
||||||
|
driver.execute_script(instructions)
|
||||||
|
tour_on = True
|
||||||
|
if autoplay:
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
latest_step = 0
|
||||||
|
while tour_on:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
if browser != "firefox":
|
||||||
|
result = driver.execute_script(
|
||||||
|
"return $tour._currentStep")
|
||||||
|
else:
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, ".introjs-tooltip",
|
||||||
|
by=By.CSS_SELECTOR, timeout=0.4)
|
||||||
|
result = True
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
result = None
|
||||||
|
if result is not None:
|
||||||
|
tour_on = True
|
||||||
|
if autoplay:
|
||||||
|
try:
|
||||||
|
current_step = driver.execute_script(
|
||||||
|
"return $tour._currentStep")
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
if current_step != latest_step:
|
||||||
|
latest_step = current_step
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
now_ms = time.time() * 1000.0
|
||||||
|
if now_ms >= stop_ms:
|
||||||
|
if current_step == latest_step:
|
||||||
|
driver.execute_script("return $tour.nextStep()")
|
||||||
|
try:
|
||||||
|
latest_step = driver.execute_script(
|
||||||
|
"return $tour._currentStep")
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (interval * 1000.0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
time.sleep(0.01)
|
||||||
|
if browser != "firefox":
|
||||||
|
result = driver.execute_script(
|
||||||
|
"return $tour._currentStep")
|
||||||
|
else:
|
||||||
|
page_actions.wait_for_element_present(
|
||||||
|
driver, ".introjs-tooltip",
|
||||||
|
by=By.CSS_SELECTOR, timeout=0.4)
|
||||||
|
result = True
|
||||||
|
if result is not None:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
tour_on = False
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def export_tour(tour_steps, name=None, filename="my_tour.js"):
|
||||||
|
""" Exports a tour as a JS file.
|
||||||
|
It will include necessary resources as well, such as jQuery.
|
||||||
|
You'll be able to copy the tour directly into the Console of
|
||||||
|
any web browser to play the tour outside of SeleniumBase runs. """
|
||||||
|
if not name:
|
||||||
|
name = "default"
|
||||||
|
if name not in tour_steps:
|
||||||
|
raise Exception("Tour {%s} does not exist!" % name)
|
||||||
|
if not filename.endswith('.js'):
|
||||||
|
raise Exception('Tour file must end in ".js"!')
|
||||||
|
|
||||||
|
tour_type = None
|
||||||
|
if "Bootstrap" in tour_steps[name][0]:
|
||||||
|
tour_type = "bootstrap"
|
||||||
|
elif "Hopscotch" in tour_steps[name][0]:
|
||||||
|
tour_type = "hopscotch"
|
||||||
|
elif "IntroJS" in tour_steps[name][0]:
|
||||||
|
tour_type = "introjs"
|
||||||
|
elif "Shepherd" in tour_steps[name][0]:
|
||||||
|
tour_type = "shepherd"
|
||||||
|
else:
|
||||||
|
raise Exception('Unknown tour type!')
|
||||||
|
|
||||||
|
instructions = (
|
||||||
|
'''//////// Resources ////////\n\n'''
|
||||||
|
'''function injectCSS(css_link) {'''
|
||||||
|
'''var head = document.getElementsByTagName("head")[0];'''
|
||||||
|
'''var link = document.createElement("link");'''
|
||||||
|
'''link.rel = "stylesheet";'''
|
||||||
|
'''link.type = "text/css";'''
|
||||||
|
'''link.href = css_link;'''
|
||||||
|
'''link.crossorigin = "anonymous";'''
|
||||||
|
'''head.appendChild(link);'''
|
||||||
|
'''};\n'''
|
||||||
|
'''function injectJS(js_link) {'''
|
||||||
|
'''var head = document.getElementsByTagName("head")[0];'''
|
||||||
|
'''var script = document.createElement("script");'''
|
||||||
|
'''script.src = js_link;'''
|
||||||
|
'''script.defer;'''
|
||||||
|
'''script.type="text/javascript";'''
|
||||||
|
'''script.crossorigin = "anonymous";'''
|
||||||
|
'''script.onload = function() { null };'''
|
||||||
|
'''head.appendChild(script);'''
|
||||||
|
'''};\n'''
|
||||||
|
'''function injectStyle(css) {'''
|
||||||
|
'''var head = document.getElementsByTagName("head")[0];'''
|
||||||
|
'''var style = document.createElement("style");'''
|
||||||
|
'''style.type = "text/css";'''
|
||||||
|
'''style.appendChild(document.createTextNode(css));'''
|
||||||
|
'''head.appendChild(style);'''
|
||||||
|
'''};\n''')
|
||||||
|
|
||||||
|
if tour_type == "bootstrap":
|
||||||
|
jquery_js = constants.JQuery.MIN_JS
|
||||||
|
bootstrap_tour_css = constants.BootstrapTour.MIN_CSS
|
||||||
|
bootstrap_tour_js = constants.BootstrapTour.MIN_JS
|
||||||
|
backdrop_style = style_sheet.bt_backdrop_style
|
||||||
|
backdrop_style = backdrop_style.replace('\n', '')
|
||||||
|
backdrop_style = page_utils.escape_quotes_if_needed(backdrop_style)
|
||||||
|
instructions += 'injectJS("%s");' % jquery_js
|
||||||
|
instructions += '\n\n//////// Resources - Load 2 ////////\n\n'
|
||||||
|
instructions += 'injectCSS("%s");\n' % bootstrap_tour_css
|
||||||
|
instructions += 'injectStyle("%s");\n' % backdrop_style
|
||||||
|
instructions += 'injectJS("%s");' % bootstrap_tour_js
|
||||||
|
|
||||||
|
elif tour_type == "hopscotch":
|
||||||
|
hopscotch_css = constants.Hopscotch.MIN_CSS
|
||||||
|
hopscotch_js = constants.Hopscotch.MIN_JS
|
||||||
|
backdrop_style = style_sheet.hops_backdrop_style
|
||||||
|
backdrop_style = backdrop_style.replace('\n', '')
|
||||||
|
backdrop_style = page_utils.escape_quotes_if_needed(backdrop_style)
|
||||||
|
instructions += 'injectCSS("%s");\n' % hopscotch_css
|
||||||
|
instructions += 'injectStyle("%s");\n' % backdrop_style
|
||||||
|
instructions += 'injectJS("%s");' % hopscotch_js
|
||||||
|
|
||||||
|
elif tour_type == "introjs":
|
||||||
|
intro_css = constants.IntroJS.MIN_CSS
|
||||||
|
intro_js = constants.IntroJS.MIN_JS
|
||||||
|
instructions += 'injectCSS("%s");\n' % intro_css
|
||||||
|
instructions += 'injectJS("%s");' % intro_js
|
||||||
|
|
||||||
|
elif tour_type == "shepherd":
|
||||||
|
jquery_js = constants.JQuery.MIN_JS
|
||||||
|
shepherd_js = constants.Shepherd.MIN_JS
|
||||||
|
sh_theme_arrows_css = constants.Shepherd.THEME_ARROWS_CSS
|
||||||
|
sh_theme_arrows_fix_css = constants.Shepherd.THEME_ARR_FIX_CSS
|
||||||
|
sh_theme_default_css = constants.Shepherd.THEME_DEFAULT_CSS
|
||||||
|
sh_theme_dark_css = constants.Shepherd.THEME_DARK_CSS
|
||||||
|
sh_theme_sq_css = constants.Shepherd.THEME_SQ_CSS
|
||||||
|
sh_theme_sq_dark_css = constants.Shepherd.THEME_SQ_DK_CSS
|
||||||
|
tether_js = constants.Tether.MIN_JS
|
||||||
|
spinner_css = constants.Messenger.SPINNER_CSS
|
||||||
|
backdrop_style = style_sheet.sh_backdrop_style
|
||||||
|
backdrop_style = backdrop_style.replace('\n', '')
|
||||||
|
backdrop_style = page_utils.escape_quotes_if_needed(backdrop_style)
|
||||||
|
instructions += 'injectCSS("%s");\n' % spinner_css
|
||||||
|
instructions += 'injectJS("%s");\n' % jquery_js
|
||||||
|
instructions += 'injectJS("%s");' % tether_js
|
||||||
|
instructions += '\n\n//////// Resources - Load 2 ////////\n\n'
|
||||||
|
instructions += 'injectCSS("%s");' % sh_theme_arrows_css
|
||||||
|
instructions += 'injectCSS("%s");' % sh_theme_arrows_fix_css
|
||||||
|
instructions += 'injectCSS("%s");' % sh_theme_default_css
|
||||||
|
instructions += 'injectCSS("%s");' % sh_theme_dark_css
|
||||||
|
instructions += 'injectCSS("%s");' % sh_theme_sq_css
|
||||||
|
instructions += 'injectCSS("%s");\n' % sh_theme_sq_dark_css
|
||||||
|
instructions += 'injectStyle("%s");\n' % backdrop_style
|
||||||
|
instructions += 'injectJS("%s");' % shepherd_js
|
||||||
|
|
||||||
|
instructions += '\n\n//////// Tour Code ////////\n\n'
|
||||||
|
for tour_step in tour_steps[name]:
|
||||||
|
instructions += tour_step
|
||||||
|
|
||||||
|
if tour_type == "bootstrap":
|
||||||
|
instructions += (
|
||||||
|
"""]);
|
||||||
|
// Initialize the tour
|
||||||
|
tour.init();
|
||||||
|
// Start the tour
|
||||||
|
tour.start();
|
||||||
|
$tour = tour;
|
||||||
|
$tour.restart();\n
|
||||||
|
""")
|
||||||
|
elif tour_type == "hopscotch":
|
||||||
|
instructions += (
|
||||||
|
"""]
|
||||||
|
};
|
||||||
|
// Start the tour!
|
||||||
|
hopscotch.startTour(tour);
|
||||||
|
$tour = hopscotch;\n
|
||||||
|
""")
|
||||||
|
elif tour_type == "introjs":
|
||||||
|
instructions += (
|
||||||
|
"""]
|
||||||
|
});
|
||||||
|
intro.setOption("disableInteraction", true);
|
||||||
|
intro.setOption("overlayOpacity", .29);
|
||||||
|
intro.setOption("scrollToElement", true);
|
||||||
|
intro.setOption("keyboardNavigation", true);
|
||||||
|
intro.setOption("exitOnEsc", false);
|
||||||
|
intro.setOption("exitOnOverlayClick", false);
|
||||||
|
intro.setOption("showStepNumbers", false);
|
||||||
|
intro.setOption("showProgress", false);
|
||||||
|
intro.start();
|
||||||
|
$tour = intro;
|
||||||
|
};
|
||||||
|
startIntro();\n
|
||||||
|
""")
|
||||||
|
elif tour_type == "shepherd":
|
||||||
|
instructions += (
|
||||||
|
"""
|
||||||
|
tour.start();
|
||||||
|
$tour = tour;\n
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
out_file = codecs.open(filename, "w+")
|
||||||
|
out_file.writelines(instructions)
|
||||||
|
out_file.close()
|
||||||
|
print('\n>>> [%s] was saved!\n' % filename)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,550 @@
|
||||||
|
"""
|
||||||
|
This module contains useful Javascript utility methods for base_case.py
|
||||||
|
These helper methods SHOULD NOT be called directly from tests.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
from selenium.common.exceptions import WebDriverException
|
||||||
|
from seleniumbase.config import settings
|
||||||
|
from seleniumbase.fixtures import constants
|
||||||
|
from seleniumbase.fixtures import page_utils
|
||||||
|
|
||||||
|
|
||||||
|
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. """
|
||||||
|
try:
|
||||||
|
# Let's first find out if jQuery is already defined.
|
||||||
|
driver.execute_script("jQuery('html')")
|
||||||
|
# Since that command worked, jQuery is defined. Let's return.
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
# jQuery is not currently defined. Let's proceed by defining it.
|
||||||
|
pass
|
||||||
|
jquery_js = constants.JQuery.MIN_JS
|
||||||
|
activate_jquery_script = (
|
||||||
|
'''var script = document.createElement('script');'''
|
||||||
|
'''script.src = "%s";document.getElementsByTagName('head')[0]'''
|
||||||
|
'''.appendChild(script);''' % jquery_js)
|
||||||
|
driver.execute_script(activate_jquery_script)
|
||||||
|
for x in range(int(settings.MINI_TIMEOUT * 10.0)):
|
||||||
|
# jQuery needs a small amount of time to activate.
|
||||||
|
try:
|
||||||
|
driver.execute_script("jQuery('html')")
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.1)
|
||||||
|
# Since jQuery still isn't activating, give up and raise an exception
|
||||||
|
raise Exception(
|
||||||
|
'''Unable to load jQuery on "%s" due to a possible violation '''
|
||||||
|
'''of the website's Content Security Policy '''
|
||||||
|
'''directive. ''' % driver.current_url)
|
||||||
|
|
||||||
|
|
||||||
|
def safe_execute_script(driver, script):
|
||||||
|
""" When executing a script that contains a jQuery command,
|
||||||
|
it's important that the jQuery library has been loaded first.
|
||||||
|
This method will load jQuery if it wasn't already loaded. """
|
||||||
|
try:
|
||||||
|
driver.execute_script(script)
|
||||||
|
except Exception:
|
||||||
|
# The likely reason this fails is because: "jQuery is not defined"
|
||||||
|
activate_jquery(driver) # It's a good thing we can define it here
|
||||||
|
driver.execute_script(script)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_ready_state_complete(driver, timeout=settings.EXTREME_TIMEOUT):
|
||||||
|
"""
|
||||||
|
The DOM (Document Object Model) has a property called "readyState".
|
||||||
|
When the value of this becomes "complete", page resources are considered
|
||||||
|
fully loaded (although AJAX and other loads might still be happening).
|
||||||
|
This method will wait until document.readyState == "complete".
|
||||||
|
"""
|
||||||
|
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (timeout * 1000.0)
|
||||||
|
for x in range(int(timeout * 10)):
|
||||||
|
try:
|
||||||
|
ready_state = driver.execute_script("return document.readyState")
|
||||||
|
except WebDriverException:
|
||||||
|
# Bug fix for: [Permission denied to access property "document"]
|
||||||
|
time.sleep(0.03)
|
||||||
|
return True
|
||||||
|
if ready_state == u'complete':
|
||||||
|
time.sleep(0.01) # Better be sure everything is done loading
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
now_ms = time.time() * 1000.0
|
||||||
|
if now_ms >= stop_ms:
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
raise Exception(
|
||||||
|
"Page elements never fully loaded after %s seconds!" % timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def execute_async_script(driver, script, timeout=settings.EXTREME_TIMEOUT):
|
||||||
|
driver.set_script_timeout(timeout)
|
||||||
|
return driver.execute_async_script(script)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs):
|
||||||
|
if not settings.WAIT_FOR_ANGULARJS:
|
||||||
|
return
|
||||||
|
|
||||||
|
NG_WRAPPER = '%(prefix)s' \
|
||||||
|
'var $elm=document.querySelector(' \
|
||||||
|
'\'[data-ng-app],[ng-app],.ng-scope\')||document;' \
|
||||||
|
'if(window.angular && angular.getTestability){' \
|
||||||
|
'angular.getTestability($elm).whenStable(%(handler)s)' \
|
||||||
|
'}else{' \
|
||||||
|
'var $inj;try{$inj=angular.element($elm).injector()||' \
|
||||||
|
'angular.injector([\'ng\'])}catch(ex){' \
|
||||||
|
'$inj=angular.injector([\'ng\'])};$inj.get=$inj.get||' \
|
||||||
|
'$inj;$inj.get(\'$browser\').' \
|
||||||
|
'notifyWhenNoOutstandingRequests(%(handler)s)}' \
|
||||||
|
'%(suffix)s'
|
||||||
|
def_pre = 'var cb=arguments[arguments.length-1];if(window.angular){'
|
||||||
|
prefix = kwargs.pop('prefix', def_pre)
|
||||||
|
handler = kwargs.pop('handler', 'function(){cb(true)}')
|
||||||
|
suffix = kwargs.pop('suffix', '}else{cb(false)}')
|
||||||
|
script = NG_WRAPPER % {'prefix': prefix,
|
||||||
|
'handler': handler,
|
||||||
|
'suffix': suffix}
|
||||||
|
try:
|
||||||
|
execute_async_script(driver, script, timeout=timeout)
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.05)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_css_query_selector(
|
||||||
|
driver, selector, timeout=settings.SMALL_TIMEOUT):
|
||||||
|
element = None
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (timeout * 1000.0)
|
||||||
|
for x in range(int(timeout * 10)):
|
||||||
|
try:
|
||||||
|
selector = re.escape(selector)
|
||||||
|
selector = page_utils.escape_quotes_if_needed(selector)
|
||||||
|
element = driver.execute_script(
|
||||||
|
"""return document.querySelector('%s')""" % selector)
|
||||||
|
if element:
|
||||||
|
return element
|
||||||
|
except Exception:
|
||||||
|
element = None
|
||||||
|
if not element:
|
||||||
|
now_ms = time.time() * 1000.0
|
||||||
|
if now_ms >= stop_ms:
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
raise Exception(
|
||||||
|
"Element {%s} was not present after %s seconds!" % (
|
||||||
|
selector, timeout))
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_with_js(driver, selector, loops, o_bs):
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(128, 128, 128, 0.5)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
for n in range(loops):
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(255, 0, 0, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(128, 0, 128, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(0, 0, 255, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(0, 255, 0, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(128, 128, 0, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(128, 0, 128, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: %s';"""
|
||||||
|
% (selector, o_bs))
|
||||||
|
driver.execute_script(script)
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_with_jquery(driver, selector, loops, o_bs):
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(128, 128, 128, 0.5)');""" % selector
|
||||||
|
safe_execute_script(driver, script)
|
||||||
|
for n in range(loops):
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(255, 0, 0, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(128, 0, 128, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(0, 0, 255, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(0, 255, 0, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(128, 128, 0, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(128, 0, 128, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow', '%s');""" % (selector, o_bs)
|
||||||
|
driver.execute_script(script)
|
||||||
|
|
||||||
|
|
||||||
|
def add_css_link(driver, css_link):
|
||||||
|
script_to_add_css = (
|
||||||
|
"""function injectCSS(css) {
|
||||||
|
var head = document.getElementsByTagName("head")[0];
|
||||||
|
var link = document.createElement("link");
|
||||||
|
link.rel = "stylesheet";
|
||||||
|
link.type = "text/css";
|
||||||
|
link.href = css;
|
||||||
|
link.crossorigin = "anonymous";
|
||||||
|
head.appendChild(link);
|
||||||
|
}
|
||||||
|
injectCSS("%s");""")
|
||||||
|
css_link = page_utils.escape_quotes_if_needed(css_link)
|
||||||
|
driver.execute_script(script_to_add_css % css_link)
|
||||||
|
|
||||||
|
|
||||||
|
def add_js_link(driver, js_link):
|
||||||
|
script_to_add_js = (
|
||||||
|
"""function injectJS(link) {
|
||||||
|
var head = document.getElementsByTagName("head")[0];
|
||||||
|
var script = document.createElement("script");
|
||||||
|
script.src = link;
|
||||||
|
script.defer;
|
||||||
|
script.type="text/javascript";
|
||||||
|
script.crossorigin = "anonymous";
|
||||||
|
script.onload = function() { null };
|
||||||
|
head.appendChild(script);
|
||||||
|
}
|
||||||
|
injectJS("%s");""")
|
||||||
|
js_link = page_utils.escape_quotes_if_needed(js_link)
|
||||||
|
driver.execute_script(script_to_add_js % js_link)
|
||||||
|
|
||||||
|
|
||||||
|
def add_css_style(driver, css_style):
|
||||||
|
add_css_style_script = (
|
||||||
|
"""function injectStyle(css) {
|
||||||
|
var head = document.getElementsByTagName("head")[0];
|
||||||
|
var style = document.createElement("style");
|
||||||
|
style.type = "text/css";
|
||||||
|
style.appendChild(document.createTextNode(css));
|
||||||
|
head.appendChild(style);
|
||||||
|
}
|
||||||
|
injectStyle("%s");""")
|
||||||
|
css_style = css_style.replace('\n', '')
|
||||||
|
css_style = page_utils.escape_quotes_if_needed(css_style)
|
||||||
|
driver.execute_script(add_css_style_script % css_style)
|
||||||
|
|
||||||
|
|
||||||
|
def add_js_code_from_link(driver, js_link):
|
||||||
|
if js_link.startswith("//"):
|
||||||
|
js_link = "http:" + js_link
|
||||||
|
js_code = requests.get(js_link).text
|
||||||
|
add_js_code_script = (
|
||||||
|
'''var h = document.getElementsByTagName('head').item(0);'''
|
||||||
|
'''var s = document.createElement("script");'''
|
||||||
|
'''s.type = "text/javascript";'''
|
||||||
|
'''s.onload = function() { null };'''
|
||||||
|
'''s.appendChild(document.createTextNode("%s"));'''
|
||||||
|
'''h.appendChild(s);''')
|
||||||
|
js_code = js_code.replace('\n', '')
|
||||||
|
js_code = page_utils.escape_quotes_if_needed(js_code)
|
||||||
|
driver.execute_script(add_js_code_script % js_code)
|
||||||
|
|
||||||
|
|
||||||
|
def add_meta_tag(driver, http_equiv=None, content=None):
|
||||||
|
if http_equiv is None:
|
||||||
|
http_equiv = "Content-Security-Policy"
|
||||||
|
if content is None:
|
||||||
|
content = ("default-src *; style-src 'self' 'unsafe-inline'; "
|
||||||
|
"script-src: 'self' 'unsafe-inline' 'unsafe-eval'")
|
||||||
|
script_to_add_meta = (
|
||||||
|
"""function injectMeta() {
|
||||||
|
var meta = document.createElement('meta');
|
||||||
|
meta.httpEquiv = "%s";
|
||||||
|
meta.content = "%s";
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||||
|
}
|
||||||
|
injectMeta();""" % (http_equiv, content))
|
||||||
|
driver.execute_script(script_to_add_meta)
|
||||||
|
|
||||||
|
|
||||||
|
def activate_messenger(driver):
|
||||||
|
jquery_js = constants.JQuery.MIN_JS
|
||||||
|
messenger_css = constants.Messenger.MIN_CSS
|
||||||
|
messenger_js = constants.Messenger.MIN_JS
|
||||||
|
msgr_theme_flat_js = constants.Messenger.THEME_FLAT_JS
|
||||||
|
msgr_theme_future_js = constants.Messenger.THEME_FUTURE_JS
|
||||||
|
msgr_theme_flat_css = constants.Messenger.THEME_FLAT_CSS
|
||||||
|
msgr_theme_future_css = constants.Messenger.THEME_FUTURE_CSS
|
||||||
|
msgr_theme_block_css = constants.Messenger.THEME_BLOCK_CSS
|
||||||
|
msgr_theme_air_css = constants.Messenger.THEME_AIR_CSS
|
||||||
|
msgr_theme_ice_css = constants.Messenger.THEME_ICE_CSS
|
||||||
|
spinner_css = constants.Messenger.SPINNER_CSS
|
||||||
|
underscore_js = constants.Underscore.MIN_JS
|
||||||
|
backbone_js = constants.Backbone.MIN_JS
|
||||||
|
|
||||||
|
msg_style = ("Messenger.options = {'maxMessages': 8, "
|
||||||
|
"extraClasses: 'messenger-fixed "
|
||||||
|
"messenger-on-bottom messenger-on-right', "
|
||||||
|
"theme: 'future'}")
|
||||||
|
|
||||||
|
add_js_link(driver, jquery_js)
|
||||||
|
add_css_link(driver, messenger_css)
|
||||||
|
add_css_link(driver, msgr_theme_flat_css)
|
||||||
|
add_css_link(driver, msgr_theme_future_css)
|
||||||
|
add_css_link(driver, msgr_theme_block_css)
|
||||||
|
add_css_link(driver, msgr_theme_air_css)
|
||||||
|
add_css_link(driver, msgr_theme_ice_css)
|
||||||
|
add_js_link(driver, underscore_js)
|
||||||
|
add_js_link(driver, backbone_js)
|
||||||
|
add_css_link(driver, spinner_css)
|
||||||
|
add_js_link(driver, messenger_js)
|
||||||
|
add_js_link(driver, msgr_theme_flat_js)
|
||||||
|
add_js_link(driver, msgr_theme_future_js)
|
||||||
|
|
||||||
|
for x in range(int(settings.MINI_TIMEOUT * 10.0)):
|
||||||
|
# Messenger needs a small amount of time to load & activate.
|
||||||
|
try:
|
||||||
|
driver.execute_script(msg_style)
|
||||||
|
wait_for_ready_state_complete(driver)
|
||||||
|
wait_for_angularjs(driver)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def set_messenger_theme(driver, theme="default", location="default",
|
||||||
|
max_messages="default"):
|
||||||
|
if theme == "default":
|
||||||
|
theme = "future"
|
||||||
|
if location == "default":
|
||||||
|
location = "bottom_right"
|
||||||
|
if max_messages == "default":
|
||||||
|
max_messages = "8"
|
||||||
|
|
||||||
|
valid_themes = ['flat', 'future', 'block', 'air', 'ice']
|
||||||
|
if theme not in valid_themes:
|
||||||
|
raise Exception("Theme: %s is not in %s!" % (theme, valid_themes))
|
||||||
|
valid_locations = (['top_left', 'top_center', 'top_right'
|
||||||
|
'bottom_left', 'bottom_center', 'bottom_right'])
|
||||||
|
if location not in valid_locations:
|
||||||
|
raise Exception(
|
||||||
|
"Location: %s is not in %s!" % (location, valid_locations))
|
||||||
|
|
||||||
|
if location == 'top_left':
|
||||||
|
messenger_location = "messenger-on-top messenger-on-left"
|
||||||
|
elif location == 'top_center':
|
||||||
|
messenger_location = "messenger-on-top"
|
||||||
|
elif location == 'top_right':
|
||||||
|
messenger_location = "messenger-on-top messenger-on-right"
|
||||||
|
elif location == 'bottom_left':
|
||||||
|
messenger_location = "messenger-on-bottom messenger-on-left"
|
||||||
|
elif location == 'bottom_center':
|
||||||
|
messenger_location = "messenger-on-bottom"
|
||||||
|
elif location == 'bottom_right':
|
||||||
|
messenger_location = "messenger-on-bottom messenger-on-right"
|
||||||
|
|
||||||
|
msg_style = ("Messenger.options = {'maxMessages': %s, "
|
||||||
|
"extraClasses: 'messenger-fixed %s', theme: '%s'}"
|
||||||
|
% (max_messages, messenger_location, theme))
|
||||||
|
try:
|
||||||
|
driver.execute_script(msg_style)
|
||||||
|
except Exception:
|
||||||
|
activate_messenger(driver)
|
||||||
|
driver.execute_script(msg_style)
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def post_message(driver, message, msg_dur, style="info", duration=None):
|
||||||
|
""" A helper method to post a message on the screen with Messenger.
|
||||||
|
(Should only be called from post_message() in base_case.py) """
|
||||||
|
if not duration:
|
||||||
|
if not msg_dur:
|
||||||
|
duration = settings.DEFAULT_MESSAGE_DURATION
|
||||||
|
else:
|
||||||
|
duration = msg_dur
|
||||||
|
message = re.escape(message)
|
||||||
|
message = page_utils.escape_quotes_if_needed(message)
|
||||||
|
messenger_script = ('''Messenger().post({message: "%s", type: "%s", '''
|
||||||
|
'''hideAfter: %s, hideOnNavigate: true});'''
|
||||||
|
% (message, style, duration))
|
||||||
|
try:
|
||||||
|
driver.execute_script(messenger_script)
|
||||||
|
except Exception:
|
||||||
|
activate_messenger(driver)
|
||||||
|
set_messenger_theme(driver)
|
||||||
|
try:
|
||||||
|
driver.execute_script(messenger_script)
|
||||||
|
except Exception:
|
||||||
|
time.sleep(0.2)
|
||||||
|
activate_messenger(driver)
|
||||||
|
time.sleep(0.2)
|
||||||
|
set_messenger_theme(driver)
|
||||||
|
time.sleep(0.5)
|
||||||
|
driver.execute_script(messenger_script)
|
||||||
|
|
||||||
|
|
||||||
|
def post_messenger_success_message(driver, message, msg_dur, duration=None):
|
||||||
|
if not duration:
|
||||||
|
if not msg_dur:
|
||||||
|
duration = settings.DEFAULT_MESSAGE_DURATION
|
||||||
|
else:
|
||||||
|
duration = msg_dur
|
||||||
|
try:
|
||||||
|
set_messenger_theme(driver, theme="future", location="bottom_right")
|
||||||
|
post_message(
|
||||||
|
driver, message, msg_dur, style="success", duration=duration)
|
||||||
|
time.sleep(duration)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def post_messenger_error_message(driver, message, msg_dur, duration=None):
|
||||||
|
if not duration:
|
||||||
|
if not msg_dur:
|
||||||
|
duration = settings.DEFAULT_MESSAGE_DURATION
|
||||||
|
else:
|
||||||
|
duration = msg_dur
|
||||||
|
try:
|
||||||
|
set_messenger_theme(driver, theme="block", location="top_center")
|
||||||
|
post_message(
|
||||||
|
driver, message, msg_dur, style="error", duration=duration)
|
||||||
|
time.sleep(duration)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_with_js_2(driver, message, selector, o_bs, msg_dur):
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(128, 128, 128, 0.5)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(205, 30, 0, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(128, 0, 128, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(50, 50, 128, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: 0px 0px 6px 6px rgba(50, 205, 50, 1)';"""
|
||||||
|
% selector)
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
|
||||||
|
post_messenger_success_message(driver, message, msg_dur)
|
||||||
|
|
||||||
|
script = ("""document.querySelector('%s').style =
|
||||||
|
'box-shadow: %s';""" % (selector, o_bs))
|
||||||
|
driver.execute_script(script)
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_with_jquery_2(driver, message, selector, o_bs, msg_dur):
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(128, 128, 128, 0.5)');""" % selector
|
||||||
|
safe_execute_script(driver, script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(205, 30, 0, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(128, 0, 128, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(50, 50, 200, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
script = """jQuery('%s').css('box-shadow',
|
||||||
|
'0px 0px 6px 6px rgba(50, 205, 50, 1)');""" % selector
|
||||||
|
driver.execute_script(script)
|
||||||
|
time.sleep(0.0181)
|
||||||
|
|
||||||
|
post_messenger_success_message(driver, message, msg_dur)
|
||||||
|
|
||||||
|
script = """jQuery('%s').css('box-shadow', '%s');""" % (selector, o_bs)
|
||||||
|
driver.execute_script(script)
|
||||||
|
|
||||||
|
|
||||||
|
def scroll_to_element(driver, element):
|
||||||
|
element_location = element.location['y']
|
||||||
|
element_location = element_location - 130
|
||||||
|
if element_location < 0:
|
||||||
|
element_location = 0
|
||||||
|
scroll_script = "window.scrollTo(0, %s);" % element_location
|
||||||
|
# The old jQuery scroll_script required by=By.CSS_SELECTOR
|
||||||
|
# scroll_script = "jQuery('%s')[0].scrollIntoView()" % selector
|
||||||
|
try:
|
||||||
|
driver.execute_script(scroll_script)
|
||||||
|
except WebDriverException:
|
||||||
|
pass # Older versions of Firefox experienced issues here
|
||||||
|
|
||||||
|
|
||||||
|
def slow_scroll_to_element(driver, element, browser):
|
||||||
|
if browser == 'ie':
|
||||||
|
# IE breaks on slow-scrolling. Do a fast scroll instead.
|
||||||
|
scroll_to_element(driver, element)
|
||||||
|
return
|
||||||
|
scroll_position = driver.execute_script("return window.scrollY;")
|
||||||
|
element_location = element.location['y']
|
||||||
|
element_location = element_location - 130
|
||||||
|
if element_location < 0:
|
||||||
|
element_location = 0
|
||||||
|
distance = element_location - scroll_position
|
||||||
|
if distance != 0:
|
||||||
|
total_steps = int(abs(distance) / 50.0) + 2.0
|
||||||
|
step_value = float(distance) / total_steps
|
||||||
|
new_position = scroll_position
|
||||||
|
for y in range(int(total_steps)):
|
||||||
|
time.sleep(0.0114)
|
||||||
|
new_position += step_value
|
||||||
|
scroll_script = "window.scrollTo(0, %s);" % new_position
|
||||||
|
driver.execute_script(scroll_script)
|
||||||
|
time.sleep(0.01)
|
||||||
|
scroll_script = "window.scrollTo(0, %s);" % element_location
|
||||||
|
driver.execute_script(scroll_script)
|
||||||
|
time.sleep(0.01)
|
||||||
|
if distance > 430 or distance < -300:
|
||||||
|
# Add small recovery time for long-distance slow-scrolling
|
||||||
|
time.sleep(0.162)
|
|
@ -24,7 +24,6 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from selenium.common.exceptions import WebDriverException
|
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
from selenium.webdriver.common.action_chains import ActionChains
|
from selenium.webdriver.common.action_chains import ActionChains
|
||||||
from selenium.webdriver.remote.errorhandler import ElementNotVisibleException
|
from selenium.webdriver.remote.errorhandler import ElementNotVisibleException
|
||||||
|
@ -426,35 +425,6 @@ def save_test_failure_data(driver, name, browser_type, folder=None):
|
||||||
failure_data_file.close()
|
failure_data_file.close()
|
||||||
|
|
||||||
|
|
||||||
def wait_for_ready_state_complete(driver, timeout=settings.EXTREME_TIMEOUT):
|
|
||||||
"""
|
|
||||||
The DOM (Document Object Model) has a property called "readyState".
|
|
||||||
When the value of this becomes "complete", page resources are considered
|
|
||||||
fully loaded (although AJAX and other loads might still be happening).
|
|
||||||
This method will wait until document.readyState == "complete".
|
|
||||||
"""
|
|
||||||
|
|
||||||
start_ms = time.time() * 1000.0
|
|
||||||
stop_ms = start_ms + (timeout * 1000.0)
|
|
||||||
for x in range(int(timeout * 10)):
|
|
||||||
try:
|
|
||||||
ready_state = driver.execute_script("return document.readyState")
|
|
||||||
except WebDriverException:
|
|
||||||
# Bug fix for: [Permission denied to access property "document"]
|
|
||||||
time.sleep(0.03)
|
|
||||||
return True
|
|
||||||
if ready_state == u'complete':
|
|
||||||
time.sleep(0.01) # Better be sure everything is done loading
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
now_ms = time.time() * 1000.0
|
|
||||||
if now_ms >= stop_ms:
|
|
||||||
break
|
|
||||||
time.sleep(0.1)
|
|
||||||
raise Exception(
|
|
||||||
"Page elements never fully loaded after %s seconds!" % timeout)
|
|
||||||
|
|
||||||
|
|
||||||
def wait_for_and_accept_alert(driver, timeout=settings.LARGE_TIMEOUT):
|
def wait_for_and_accept_alert(driver, timeout=settings.LARGE_TIMEOUT):
|
||||||
"""
|
"""
|
||||||
Wait for and accept an alert. Returns the text from the alert.
|
Wait for and accept an alert. Returns the text from the alert.
|
||||||
|
|
|
@ -114,11 +114,20 @@ def escape_quotes_if_needed(string):
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
def make_css_match_first_element_only(selector):
|
||||||
|
# Only get the first match
|
||||||
|
last_syllable = selector.split(' ')[-1]
|
||||||
|
if ':' not in last_syllable and ':contains' not in selector:
|
||||||
|
selector += ':first'
|
||||||
|
return selector
|
||||||
|
|
||||||
|
|
||||||
def _jq_format(code):
|
def _jq_format(code):
|
||||||
"""
|
"""
|
||||||
DEPRECATED - Use re.escape() instead, which performs the intended action.
|
DEPRECATED - Use re.escape() instead, which performs the intended action.
|
||||||
Use before throwing raw code such as 'div[tab="advanced"]' into jQuery.
|
Use before throwing raw code such as 'div[tab="advanced"]' into jQuery.
|
||||||
Selectors with quotes inside of quotes would otherwise break jQuery.
|
Selectors with quotes inside of quotes would otherwise break jQuery.
|
||||||
|
If you just want to escape quotes, there's escape_quotes_if_needed().
|
||||||
This is similar to "json.dumps(value)", but with one less layer of quotes.
|
This is similar to "json.dumps(value)", but with one less layer of quotes.
|
||||||
"""
|
"""
|
||||||
code = code.replace('\\', '\\\\').replace('\t', '\\t').replace('\n', '\\n')
|
code = code.replace('\\', '\\\\').replace('\t', '\\t').replace('\n', '\\n')
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
"""
|
|
||||||
This module imports all the commonly used fixtures in one place so that
|
|
||||||
every test doesn't need to import a number of different fixtures.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from seleniumbase.fixtures.page_actions import * # noqa
|
|
||||||
from seleniumbase.fixtures.page_utils import * # noqa
|
|
||||||
from seleniumbase.fixtures.errors import * # noqa
|
|
||||||
from seleniumbase.fixtures.xpath_to_css import * # noqa
|
|
6
setup.py
6
setup.py
|
@ -17,7 +17,7 @@ except IOError:
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='seleniumbase',
|
name='seleniumbase',
|
||||||
version='1.16.4',
|
version='1.16.5',
|
||||||
description='All-In-One Test Automation Framework',
|
description='All-In-One Test Automation Framework',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
|
@ -57,13 +57,13 @@ setup(
|
||||||
'pytest>=3.8.2',
|
'pytest>=3.8.2',
|
||||||
'pytest-cov>=2.6.0',
|
'pytest-cov>=2.6.0',
|
||||||
'pytest-html>=1.19.0',
|
'pytest-html>=1.19.0',
|
||||||
'pytest-rerunfailures>=4.1',
|
'pytest-rerunfailures>=4.2',
|
||||||
'pytest-xdist>=1.23.2',
|
'pytest-xdist>=1.23.2',
|
||||||
'parameterized==0.6.1',
|
'parameterized==0.6.1',
|
||||||
|
'beautifulsoup4>=4.6.0',
|
||||||
'six>=1.11.0',
|
'six>=1.11.0',
|
||||||
'pyotp>=2.2.6',
|
'pyotp>=2.2.6',
|
||||||
'requests>=2.19.1',
|
'requests>=2.19.1',
|
||||||
'beautifulsoup4>=4.6.3',
|
|
||||||
'unittest2>=1.1.0',
|
'unittest2>=1.1.0',
|
||||||
'chardet>=3.0.4',
|
'chardet>=3.0.4',
|
||||||
'urllib3>=1.23',
|
'urllib3>=1.23',
|
||||||
|
|
Loading…
Reference in New Issue