110 lines
3.5 KiB
Python
110 lines
3.5 KiB
Python
"""
|
|
High-level tab navigation.
|
|
"""
|
|
|
|
|
|
from bok_choy.page_object import PageObject
|
|
from bok_choy.promise import EmptyPromise, Promise
|
|
|
|
|
|
class TabNavPage(PageObject):
|
|
"""
|
|
High-level tab navigation.
|
|
"""
|
|
|
|
url = None
|
|
|
|
# def is_using_v1_style_tabs(self):
|
|
# return self.q(css='ol.course-tabs').present
|
|
|
|
def is_using_boostrap_style_tabs(self):
|
|
return self.q(css='ul.navbar-nav').present
|
|
|
|
def is_browser_on_page(self):
|
|
return (self.q(css='ol.course-tabs').present or
|
|
self.q(css='ul.navbar-nav').present)
|
|
|
|
def go_to_tab(self, tab_name):
|
|
"""
|
|
Navigate to the tab `tab_name`.
|
|
"""
|
|
|
|
if tab_name not in ['Course', 'Home', 'Discussion', 'Wiki', 'Progress']:
|
|
self.warning(f"'{tab_name}' is not a valid tab name")
|
|
|
|
# The only identifier for individual tabs is the link href
|
|
# so we find the tab with `tab_name` in its text.
|
|
tab_css = self._tab_css(tab_name)
|
|
|
|
if tab_css is not None:
|
|
self.q(css=tab_css).first.click()
|
|
else:
|
|
self.warning(f"No tabs found for '{tab_name}'")
|
|
|
|
self.wait_for_page()
|
|
self._is_on_tab_promise(tab_name).fulfill()
|
|
|
|
def _tab_css(self, tab_name):
|
|
"""
|
|
Return the CSS to click for `tab_name`.
|
|
If no tabs exist for that name, return `None`.
|
|
"""
|
|
all_tabs = self.tab_names
|
|
|
|
try:
|
|
tab_index = all_tabs.index(tab_name)
|
|
except ValueError:
|
|
return None
|
|
else:
|
|
if self.is_using_boostrap_style_tabs():
|
|
return 'ul.navbar-nav li:nth-of-type({}) a'.format(tab_index + 1)
|
|
else:
|
|
return 'ol.course-tabs li:nth-of-type({}) a'.format(tab_index + 1)
|
|
|
|
@property
|
|
def tab_names(self):
|
|
"""
|
|
Return the list of available tab names. If no tab names
|
|
are available, wait for them to load. Raises a `BrokenPromiseError`
|
|
if the tab names fail to load.
|
|
"""
|
|
def _standard_check_func():
|
|
tab_names = self.q(css='ol.course-tabs li a').text
|
|
return (len(tab_names) > 0, tab_names)
|
|
|
|
def _bootstrap_check_func():
|
|
tab_names = self.q(css='ul.navbar-nav li a').text
|
|
return (len(tab_names) > 0, tab_names)
|
|
|
|
if self.is_using_boostrap_style_tabs():
|
|
return Promise(_bootstrap_check_func, "Get all tab names").fulfill()
|
|
else:
|
|
return Promise(_standard_check_func, "Get all tab names").fulfill()
|
|
|
|
def _is_on_tab(self, tab_name):
|
|
"""
|
|
Return a boolean indicating whether the current tab is `tab_name`.
|
|
This is a private method, so it does NOT enforce the page check,
|
|
which is what we want when we're polling the DOM in a promise.
|
|
"""
|
|
if self.is_using_boostrap_style_tabs():
|
|
current_tab_list = self.q(css='ul.navbar-nav > .nav-item.active').text
|
|
else:
|
|
current_tab_list = self.q(css='ol.course-tabs > li > a.active').text
|
|
|
|
if len(current_tab_list) == 0:
|
|
self.warning("Could not find current tab")
|
|
return False
|
|
else:
|
|
return current_tab_list[0].strip().split('\n')[0] == tab_name
|
|
|
|
def _is_on_tab_promise(self, tab_name):
|
|
"""
|
|
Return a `Promise` that the user is on the tab `tab_name`.
|
|
"""
|
|
# Use the private version of _is_on_tab to skip the page check
|
|
return EmptyPromise(
|
|
lambda: self._is_on_tab(tab_name),
|
|
f"{tab_name} is the current tab"
|
|
)
|