Add ability to create SeleniumBase Bootstrap Tours

This commit is contained in:
Michael Mintz 2018-08-27 11:57:14 -04:00
parent 4ea23a19b2
commit 00d1b64d1c
2 changed files with 208 additions and 26 deletions

View File

@ -91,12 +91,14 @@ self.add_css_style(css_style)
self.add_js_code_from_link(js_link)
self.add_meta_tag(http_equiv=None, content=None):
self.add_meta_tag(http_equiv=None, content=None)
self.activate_jquery()
self.create_tour(name=None, theme=None)
self.create_bootstrap_tour(name=None)
self.add_tour_step(message, selector=None, name=None,
title=None, theme=None, alignment=None)

View File

@ -813,13 +813,12 @@ class BaseCase(unittest.TestCase):
def __activate_bootstrap(self):
""" Allows you to use Bootstrap Tours with SeleniumBase
http://bootstraptour.com/
(Currently, SeleniumBase methods only use Shepherd Tours.)
"""
bootstrap_tour_css = constants.BootstrapTour.MIN_CSS
bootstrap_tour_js = constants.BootstrapTour.MIN_JS
verify_script = ("""// Instance the tour
var tour = new Tour({
var tour2 = new Tour({
});""")
for x in range(4):
@ -844,7 +843,7 @@ class BaseCase(unittest.TestCase):
def __is_bootstrap_activated(self):
verify_script = ("""// Instance the tour
var tour = new Tour({
var tour2 = new Tour({
});""")
try:
self.execute_script(verify_script)
@ -873,6 +872,8 @@ class BaseCase(unittest.TestCase):
self.__activate_bootstrap()
self.wait_for_ready_state_complete()
self.add_css_style(backdrop_style)
self.wait_for_ready_state_complete()
for x in range(4):
# self.activate_jquery() # Included with __activate_bootstrap()
self.add_css_link(spinner_css)
@ -886,8 +887,6 @@ class BaseCase(unittest.TestCase):
self.add_js_link(underscore_js)
self.add_js_link(backbone_js)
self.add_js_link(shepherd_js)
time.sleep(0.01)
self.add_css_style(backdrop_style)
time.sleep(0.1)
for x in range(int(settings.MINI_TIMEOUT * 2.0)):
@ -896,6 +895,7 @@ class BaseCase(unittest.TestCase):
self.execute_script(sh_style) # Verify Shepherd has loaded
self.wait_for_ready_state_complete()
self.execute_script(sh_style) # Need it twice for ordering
self.wait_for_ready_state_complete()
time.sleep(0.05)
return
except Exception:
@ -928,7 +928,10 @@ class BaseCase(unittest.TestCase):
shepherd_theme = "shepherd-theme-arrows"
if theme:
if theme == "default":
if theme.lower() == "bootstrap":
self.create_bootstrap_tour(name)
return
elif theme == "default":
shepherd_theme = "shepherd-theme-default"
elif theme == "dark":
shepherd_theme = "shepherd-theme-dark"
@ -939,18 +942,39 @@ class BaseCase(unittest.TestCase):
elif theme == "square-dark":
shepherd_theme = "shepherd-theme-square-dark"
new_tour = ("""let tour = new Shepherd.Tour({
new_tour = ("""
// Shepherd Tour
let tour = new Shepherd.Tour({
defaults: {
classes: '%s',
scrollTo: true
}
});""" % shepherd_theme)
});
""" % shepherd_theme)
self._tour_steps[name] = []
self._tour_steps[name].append(new_tour)
def create_bootstrap_tour(self, name=None):
""" Creates a Bootstrap tour for a website.
@Params
name - If creating multiple tours, use this to select the
tour you wish to add steps to.
"""
if not name:
name = "default"
new_tour = ("""
// Bootstrap Tour
var tour = new Tour({
steps: [
""")
self._tour_steps[name] = []
self._tour_steps[name].append(new_tour)
def add_tour_step(self, message, selector=None, name=None,
title=None, theme=None, alignment=None):
title=None, theme=None, alignment=None, duration=None):
""" Allows the user to add tour steps for a website.
@Params
message - The message to display.
@ -958,10 +982,13 @@ class BaseCase(unittest.TestCase):
name - If creating multiple tours, use this to select the
tour you wish to add steps to.
title - Additional header text that appears above the message.
theme - Choose from "arrows", "dark", "default", "square", and
theme - (NON-Bootstrap Tours ONLY) The styling of the tour step.
Choose from "arrows", "dark", "default", "square", and
"square-dark". ("arrows" is used if None is selected.)
alignment - Choose from "top", "bottom", "left", and "right".
("top" is the default alignment).
duration - (Bootstrap Tours ONLY) The amount of time, in seconds,
before automatically advancing to the next tour step.
"""
if not selector:
selector = "html"
@ -970,7 +997,8 @@ class BaseCase(unittest.TestCase):
if not name:
name = "default"
if name not in self._tour_steps:
self.create_tour(name=name)
# By default, will create a Bootstrap tour if no tours exist
self.create_tour(name=name, theme="bootstrap")
if not title:
title = ""
@ -981,6 +1009,34 @@ class BaseCase(unittest.TestCase):
else:
message = ""
if not alignment or (
alignment not in ["top", "bottom", "left", "right"]):
alignment = "top"
if "Bootstrap" in self._tour_steps[name][0]:
self.__add_bootstrap_tour_step(
message, selector=selector, name=name, title=title,
alignment=alignment, duration=duration)
else:
self.__add_shepherd_tour_step(
message, selector=selector, name=name, title=title,
theme=theme, alignment=alignment)
def __add_shepherd_tour_step(self, message, selector=None, name=None,
title=None, theme=None, alignment=None):
""" Allows the user to add tour steps for a website.
@Params
message - The message to display.
selector - The CSS Selector of the Element to attach to.
name - If creating multiple tours, use this to select the
tour you wish to add steps to.
title - Additional header text that appears above the message.
theme - (NON-Bootstrap Tours ONLY) The styling of the tour step.
Choose from "arrows", "dark", "default", "square", and
"square-dark". ("arrows" is used if None is selected.)
alignment - Choose from "top", "bottom", "left", and "right".
("top" is the default alignment).
"""
if theme == "default":
shepherd_theme = "shepherd-theme-default"
elif theme == "dark":
@ -997,10 +1053,6 @@ class BaseCase(unittest.TestCase):
self._tour_steps[name][0]).group(1)
shepherd_theme = shepherd_base_theme
if not alignment or (
alignment not in ["top", "bottom", "left", "right"]):
alignment = "top"
shepherd_classes = shepherd_theme
if selector == "html":
shepherd_classes += " shepherd-orphan"
@ -1016,6 +1068,41 @@ class BaseCase(unittest.TestCase):
self._tour_steps[name].append(step)
def __add_bootstrap_tour_step(self, message, selector=None, name=None,
title=None, alignment=None, duration=None):
""" Allows the user to add tour steps for a website.
@Params
message - The message to display.
selector - The CSS Selector of the Element to attach to.
name - If creating multiple tours, use this to select the
tour you wish to add steps to.
title - Additional header text that appears above the message.
alignment - Choose from "top", "bottom", "left", and "right".
("top" is the default alignment).
duration - (Bootstrap Tours ONLY) The amount of time, in seconds,
before automatically advancing to the next tour step.
"""
if selector != "html":
element_row = "element: '%s'," % selector
else:
element_row = ""
if not duration:
duration = "0"
else:
duration = str(float(duration) * 1000.0)
step = ("""{
%s
title: '%s',
content: '%s',
orphan: true,
placement: 'auto %s',
smartPlacement: true,
duration: %s,
},""" % (element_row, title, message, alignment, duration))
self._tour_steps[name].append(step)
def play_tour(self, name=None, interval=0):
""" Plays a tour on the current website.
@Params
@ -1027,6 +1114,29 @@ class BaseCase(unittest.TestCase):
if self.headless:
return # Tours should not run in headless mode.
if not name:
name = "default"
if name not in self._tour_steps:
raise Exception("Tour {%s} does not exist!" % name)
if "Bootstrap" in self._tour_steps[name][0]:
self.__play_bootstrap_tour(name=name, interval=interval)
else:
self.__play_shepherd_tour(name=name, interval=interval)
def __play_shepherd_tour(self, name=None, interval=0):
""" Plays a tour on the current website.
@Params
name - If creating multiple tours, use this to select the
tour you wish to play.
interval - The delay time between autoplaying tour steps.
If set to 0 (default), the tour is fully manual control.
"""
instructions = ""
for tour_step in self._tour_steps[name]:
instructions += tour_step
instructions += "tour.start();"
autoplay = False
if interval and interval > 0:
autoplay = True
@ -1034,16 +1144,6 @@ class BaseCase(unittest.TestCase):
if interval < 0.5:
interval = 0.5
if not name:
name = "default"
if name not in self._tour_steps:
raise Exception("Tour {%s} does not exist!" % name)
instructions = ""
for tour_step in self._tour_steps[name]:
instructions += tour_step
instructions += "tour.start();"
if not self.__is_shepherd_activated():
self.__activate_shepherd()
@ -1134,6 +1234,86 @@ class BaseCase(unittest.TestCase):
tour_on = False
time.sleep(0.1)
def __play_bootstrap_tour(self, name=None, interval=0):
""" Plays a tour on the current website.
@Params
name - If creating multiple tours, use this to select the
tour you wish to play.
interval - The delay time between autoplaying tour steps.
If set to 0 (default), the tour is fully manual control.
"""
instructions = ""
for tour_step in self._tour_steps[name]:
instructions += tour_step
instructions += (
"""]});
// Initialize the tour
tour.init();
// Start the tour
tour.start();
$tour = tour;
$tour.restart();""")
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 self.__is_bootstrap_activated():
self.__activate_bootstrap()
if len(self._tour_steps[name]) > 1:
try:
if "element: " in self._tour_steps[name][1]:
selector = re.search(
"[\S\s]+element: '([\S\s]+)',[\S\s]+title: '",
self._tour_steps[name][1]).group(1)
selector = selector.replace('\\', '')
self.wait_for_element_present(
selector, timeout=(settings.SMALL_TIMEOUT))
else:
selector = "html"
except Exception:
self.__post_messenger_error_message(
"Tour Error: {'%s'} was not found!"
"" % selector,
duration=settings.SMALL_TIMEOUT)
raise Exception(
"Tour Error: {'%s'} was not found! "
"Exiting due to failure on first tour step!"
"" % selector)
self.execute_script(instructions)
tour_on = True
while tour_on:
try:
time.sleep(0.01)
result = self.execute_script(
"return $tour.ended()")
except Exception:
tour_on = False
result = None
if result is False:
tour_on = True
else:
try:
time.sleep(0.01)
result = self.execute_script(
"return $tour.ended()")
if result is False:
time.sleep(0.1)
continue
else:
return
except Exception:
tour_on = False
time.sleep(0.1)
def __wait_for_css_query_selector(
self, selector, timeout=settings.SMALL_TIMEOUT):
element = None