Skip to content

Commit c3d44d4

Browse files
committed
Add the ability to create DriverJS website tours
1 parent 796e6b8 commit c3d44d4

File tree

4 files changed

+290
-6
lines changed

4 files changed

+290
-6
lines changed

seleniumbase/core/style_sheet.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@
116116
}
117117
''')
118118

119+
# DriverJS Tour Backdrop Style
120+
dt_backdrop_style = (
121+
'''
122+
.driver-fix-stacking {
123+
pointer-events: none !important;
124+
}
125+
#driver-popover-item, .popover-class {
126+
pointer-events: auto !important;
127+
}
128+
''')
129+
119130
messenger_style = (
120131
'''
121132
.messenger-message-inner {

seleniumbase/core/tour_helper.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,51 @@ def is_bootstrap_activated(driver):
5656
return False
5757

5858

59+
def activate_driverjs(driver):
60+
""" Allows you to use DriverJS Tours with SeleniumBase
61+
https://kamranahmed.info/driver.js/
62+
"""
63+
backdrop_style = style_sheet.dt_backdrop_style
64+
driverjs_css = constants.DriverJS.MIN_CSS
65+
driverjs_js = constants.DriverJS.MIN_JS
66+
67+
verify_script = ("""// Verify DriverJS activated
68+
var driverjs2 = Driver.name;
69+
""")
70+
71+
activate_bootstrap(driver)
72+
js_utils.wait_for_ready_state_complete(driver)
73+
js_utils.wait_for_angularjs(driver)
74+
js_utils.add_css_style(driver, backdrop_style)
75+
for x in range(4):
76+
js_utils.activate_jquery(driver)
77+
js_utils.add_css_link(driver, driverjs_css)
78+
js_utils.add_js_link(driver, driverjs_js)
79+
time.sleep(0.1)
80+
for x in range(int(settings.MINI_TIMEOUT * 2.0)):
81+
# DriverJS needs a small amount of time to load & activate.
82+
try:
83+
driver.execute_script(verify_script)
84+
js_utils.wait_for_ready_state_complete(driver)
85+
js_utils.wait_for_angularjs(driver)
86+
time.sleep(0.05)
87+
return
88+
except Exception:
89+
time.sleep(0.15)
90+
js_utils.raise_unable_to_load_jquery_exception(driver)
91+
92+
93+
def is_driverjs_activated(driver):
94+
verify_script = ("""// Verify DriverJS activated
95+
var driverjs2 = Driver.name;
96+
""")
97+
try:
98+
driver.execute_script(verify_script)
99+
return True
100+
except Exception:
101+
return False
102+
103+
59104
def activate_hopscotch(driver):
60105
""" Allows you to use Hopscotch Tours with SeleniumBase
61106
http://linkedin.github.io/hopscotch/
@@ -399,6 +444,118 @@ def play_bootstrap_tour(
399444
time.sleep(0.1)
400445

401446

447+
def play_driverjs_tour(
448+
driver, tour_steps, browser, msg_dur, name=None, interval=0):
449+
""" Plays a DriverJS tour on the current website. """
450+
instructions = ""
451+
for tour_step in tour_steps[name]:
452+
instructions += tour_step
453+
instructions += (
454+
"""]
455+
);
456+
// Start the tour!
457+
tour.start();
458+
$tour = tour;""")
459+
autoplay = False
460+
if interval and interval > 0:
461+
autoplay = True
462+
interval = float(interval)
463+
if interval < 0.5:
464+
interval = 0.5
465+
466+
if not is_driverjs_activated(driver):
467+
activate_driverjs(driver)
468+
469+
if len(tour_steps[name]) > 1:
470+
try:
471+
if "element: " in tour_steps[name][1]:
472+
selector = re.search(
473+
r"[\S\s]+element: '([\S\s]+)',[\S\s]+popover: {",
474+
tour_steps[name][1]).group(1)
475+
selector = selector.replace('\\', '').replace(':first', '')
476+
page_actions.wait_for_element_present(
477+
driver, selector, by=By.CSS_SELECTOR,
478+
timeout=settings.SMALL_TIMEOUT)
479+
else:
480+
selector = "html"
481+
except Exception:
482+
js_utils.post_messenger_error_message(
483+
driver, "Tour Error: {'%s'} was not found!" % selector,
484+
msg_dur)
485+
raise Exception(
486+
"Tour Error: {'%s'} was not found! "
487+
"Exiting due to failure on first tour step!"
488+
"" % selector)
489+
490+
driver.execute_script(instructions)
491+
driver.execute_script(
492+
'document.querySelector(".driver-next-btn").focus();')
493+
tour_on = True
494+
if autoplay:
495+
start_ms = time.time() * 1000.0
496+
stop_ms = start_ms + (interval * 1000.0)
497+
latest_step = 0
498+
while tour_on:
499+
try:
500+
time.sleep(0.01)
501+
if browser != "firefox":
502+
result = not driver.execute_script(
503+
"return $tour.isActivated")
504+
else:
505+
page_actions.wait_for_element_present(
506+
driver, "#driver-popover-item",
507+
by=By.CSS_SELECTOR, timeout=0.4)
508+
result = False
509+
except Exception:
510+
tour_on = False
511+
result = None
512+
if result is False:
513+
tour_on = True
514+
driver.execute_script(
515+
'document.querySelector(".driver-next-btn").focus();')
516+
if autoplay:
517+
try:
518+
current_step = driver.execute_script(
519+
"return $tour.currentStep")
520+
except Exception:
521+
continue
522+
if current_step != latest_step:
523+
latest_step = current_step
524+
start_ms = time.time() * 1000.0
525+
stop_ms = start_ms + (interval * 1000.0)
526+
now_ms = time.time() * 1000.0
527+
if now_ms >= stop_ms:
528+
if current_step == latest_step:
529+
driver.execute_script("$tour.moveNext()")
530+
try:
531+
latest_step = driver.execute_script(
532+
"return $tour.currentStep")
533+
start_ms = time.time() * 1000.0
534+
stop_ms = start_ms + (interval * 1000.0)
535+
except Exception:
536+
pass
537+
continue
538+
else:
539+
try:
540+
time.sleep(0.01)
541+
if browser != "firefox":
542+
result = not driver.execute_script(
543+
"return $tour.isActivated")
544+
else:
545+
page_actions.wait_for_element_present(
546+
driver, "#driver-popover-item",
547+
by=By.CSS_SELECTOR, timeout=0.4)
548+
result = False
549+
if result is False:
550+
time.sleep(0.1)
551+
continue
552+
else:
553+
return
554+
except Exception:
555+
tour_on = False
556+
time.sleep(0.1)
557+
558+
402559
def play_hopscotch_tour(
403560
driver, tour_steps, browser, msg_dur, name=None, interval=0):
404561
""" Plays a Hopscotch tour on the current website. """
@@ -645,6 +802,8 @@ def export_tour(tour_steps, name=None, filename="my_tour.js", url=None):
645802
tour_type = None
646803
if "Bootstrap" in tour_steps[name][0]:
647804
tour_type = "bootstrap"
805+
elif "DriverJS" in tour_steps[name][0]:
806+
tour_type = "driverjs"
648807
elif "Hopscotch" in tour_steps[name][0]:
649808
tour_type = "hopscotch"
650809
elif "IntroJS" in tour_steps[name][0]:
@@ -705,6 +864,16 @@ def export_tour(tour_steps, name=None, filename="my_tour.js", url=None):
705864
instructions += '} }\n'
706865
instructions += 'loadResources()'
707866

867+
elif tour_type == "driverjs":
868+
driverjs_css = constants.DriverJS.MIN_CSS
869+
driverjs_js = constants.DriverJS.MIN_JS
870+
backdrop_style = style_sheet.dt_backdrop_style
871+
backdrop_style = backdrop_style.replace('\n', '')
872+
backdrop_style = js_utils.escape_quotes_if_needed(backdrop_style)
873+
instructions += 'injectCSS("%s");\n' % driverjs_css
874+
instructions += 'injectStyle("%s");\n' % backdrop_style
875+
instructions += 'injectJS("%s");' % driverjs_js
876+
708877
elif tour_type == "hopscotch":
709878
hopscotch_css = constants.Hopscotch.MIN_CSS
710879
hopscotch_js = constants.Hopscotch.MIN_JS
@@ -757,6 +926,9 @@ def export_tour(tour_steps, name=None, filename="my_tour.js", url=None):
757926
if tour_type == "bootstrap":
758927
instructions += 'function loadTour() { '
759928
instructions += 'if ( typeof Tour !== "undefined" ) {\n'
929+
elif tour_type == "driverjs":
930+
instructions += 'function loadTour() { '
931+
instructions += 'if ( typeof Driver !== "undefined" ) {\n'
760932
elif tour_type == "hopscotch":
761933
instructions += 'function loadTour() { '
762934
instructions += 'if ( typeof hopscotch !== "undefined" ) {\n'
@@ -779,6 +951,13 @@ def export_tour(tour_steps, name=None, filename="my_tour.js", url=None):
779951
tour.start();
780952
$tour = tour;
781953
$tour.restart();\n""")
954+
elif tour_type == "driverjs":
955+
instructions += (
956+
"""]
957+
);
958+
// Start the tour!
959+
tour.start();
960+
$tour = tour;\n""")
782961
elif tour_type == "hopscotch":
783962
instructions += (
784963
"""]

0 commit comments

Comments
 (0)