diff --git a/notebook/static/tree/js/notebooklist.js b/notebook/static/tree/js/notebooklist.js index 7f96b2bac3..4312af2132 100644 --- a/notebook/static/tree/js/notebooklist.js +++ b/notebook/static/tree/js/notebooklist.js @@ -102,6 +102,7 @@ define([ this.sessions = {}; this.base_url = options.base_url || utils.get_body_data("baseUrl"); this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath"); + this.initial_notebook_path = this.notebook_path; this.contents = options.contents; if (this.session_list && this.session_list.events) { this.session_list.events.on('sessions_loaded.Dashboard', @@ -358,7 +359,8 @@ define([ var that = this; // Add an event handler browser back and forward events window.onpopstate = function(e) { - var path = window.history.state ? window.history.state.path : ''; + var path = (window.history.state && window.history.state.path) ? + window.history.state.path : that.initial_notebook_path; that.update_location(path); }; var breadcrumb = $('.breadcrumb'); diff --git a/notebook/tests/selenium/conftest.py b/notebook/tests/selenium/conftest.py index 9d0d082a1d..d7227b12b0 100644 --- a/notebook/tests/selenium/conftest.py +++ b/notebook/tests/selenium/conftest.py @@ -63,8 +63,8 @@ def notebook_server(): requests.post(urljoin(info['url'], 'api/shutdown'), headers={'Authorization': 'token '+info['token']}) - -def _get_selenium_driver(): +@pytest.fixture(scope='session') +def selenium_driver(): if os.environ.get('SAUCE_USERNAME'): username = os.environ["SAUCE_USERNAME"] access_key = os.environ["SAUCE_ACCESS_KEY"] @@ -81,16 +81,20 @@ def _get_selenium_driver(): capabilities['version'] = '57.0' hub_url = "%s:%s@localhost:4445" % (username, access_key) print("Connecting remote driver on Sauce Labs") - return Remote(desired_capabilities=capabilities, + driver = Remote(desired_capabilities=capabilities, command_executor="http://%s/wd/hub" % hub_url) elif os.environ.get('JUPYTER_TEST_BROWSER') == 'chrome': - return Chrome() + driver = Chrome() else: - return Firefox() + driver = Firefox() + + yield driver + + # Teardown + driver.quit() @pytest.fixture -def browser(notebook_server): - b = _get_selenium_driver() - b.get("{url}?token={token}".format(**notebook_server)) - yield b - b.quit() +def authenticated_browser(selenium_driver, notebook_server): + selenium_driver.jupyter_server_info = notebook_server + selenium_driver.get("{url}?token={token}".format(**notebook_server)) + return selenium_driver diff --git a/notebook/tests/selenium/test_dashboard_nav.py b/notebook/tests/selenium/test_dashboard_nav.py index b273ca9076..9b588c75e4 100644 --- a/notebook/tests/selenium/test_dashboard_nav.py +++ b/notebook/tests/selenium/test_dashboard_nav.py @@ -4,42 +4,76 @@ from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC +from notebook.utils import url_path_join pjoin = os.path.join + +class PageError(Exception): + """Error for an action being incompatible with the current jupyter web page. + + """ + def __init__(self, message): + self.message = message + + +def url_in_tree(browser, url=None): + if url is None: + url = browser.current_url + tree_url = url_path_join(browser.jupyter_server_info['url'], 'tree') + return url.startswith(tree_url) + + def get_list_items(browser): + """Gets list items from a directory listing page + + Raises PageError if not in directory listing page (url has tree in it) + """ + if not url_in_tree(browser): + raise PageError("You are not in the notebook's file tree view." + "This function can only be used the file tree context.") + # we need to make sure that at least one item link loads + wait_for_selector(browser, '.item_link') + return [{ 'link': a.get_attribute('href'), 'label': a.find_element_by_class_name('item_name').text, + 'element': a, } for a in browser.find_elements_by_class_name('item_link')] +def only_dir_links(browser): + """Return only links that point at other directories in the tree + + """ + items = get_list_items(browser) + return [i for i in items + if url_in_tree(browser, i['link']) and i['label'] != '..'] + + def wait_for_selector(browser, selector, timeout=10): wait = WebDriverWait(browser, timeout) return wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector))) +def test_items(authenticated_browser): + visited_dict = {} + # Going down the tree to collect links + while True: + wait_for_selector(authenticated_browser, '.item_link') + current_url = authenticated_browser.current_url + items = visited_dict[current_url] = only_dir_links(authenticated_browser) + try: + item = items[0] + item["element"].click() + assert authenticated_browser.current_url == item['link'] + except IndexError: + break + # Going back up the tree while we still have unvisited links + while visited_dict: + current_items = only_dir_links(authenticated_browser) + current_items_links = [item["link"] for item in current_items] + stored_items = visited_dict.pop(authenticated_browser.current_url) + stored_items_links = [item["link"] for item in stored_items] + assert stored_items_links == current_items_links + authenticated_browser.back() -def test_items(browser, visited=None): - tree_root_url = browser.current_url - if visited is None: - visited = set() - - wait_for_selector(browser, '.item_link') - items = get_list_items(browser) - print(browser.current_url, len(items)) - for item in items: - print(item) - url = item['link'] - if url.startswith(tree_root_url): - print("Going to", url) - if url in visited: - continue - visited.add(url) - browser.get(url) - wait_for_selector(browser, '.item_link') - assert browser.current_url == url - - test_items(browser, visited) - #browser.back() - - print()