Skip to content

Commit

Permalink
Merge pull request #3458 from mpacer/selenium_utils
Browse files Browse the repository at this point in the history
Selenium utils + markdown rendering tests
  • Loading branch information
takluyver committed Mar 28, 2018
2 parents dc1eeab + 7266fd5 commit faa0cab
Show file tree
Hide file tree
Showing 5 changed files with 355 additions and 27 deletions.
56 changes: 36 additions & 20 deletions notebook/tests/selenium/conftest.py
Expand Up @@ -12,6 +12,7 @@

pjoin = os.path.join


def _wait_for_server(proc, info_file_path):
"""Wait 30 seconds for the notebook server to start"""
for i in range(300):
Expand All @@ -28,6 +29,7 @@ def _wait_for_server(proc, info_file_path):
time.sleep(0.1)
raise RuntimeError("Didn't find %s in 30 seconds", info_file_path)


@pytest.fixture(scope='session')
def notebook_server():
info = {}
Expand All @@ -50,10 +52,11 @@ def notebook_server():
# run with a base URL that would be escaped,
# to test that we don't double-escape URLs
'--NotebookApp.base_url=/a@b/',
]
]
print("command=", command)
proc = info['popen'] = Popen(command, cwd=nbdir, env=env)
info_file_path = pjoin(td, 'jupyter_runtime', 'nbserver-%i.json' % proc.pid)
info_file_path = pjoin(td, 'jupyter_runtime',
'nbserver-%i.json' % proc.pid)
info.update(_wait_for_server(proc, info_file_path))

print("Notebook server info:", info)
Expand All @@ -63,26 +66,38 @@ def notebook_server():
requests.post(urljoin(info['url'], 'api/shutdown'),
headers={'Authorization': 'token '+info['token']})


def make_sauce_driver():
"""This function helps travis create a driver on Sauce Labs.
This function will err if used without specifying the variables expected
in that context.
"""

username = os.environ["SAUCE_USERNAME"]
access_key = os.environ["SAUCE_ACCESS_KEY"]
capabilities = {
"tunnel-identifier": os.environ["TRAVIS_JOB_NUMBER"],
"build": os.environ["TRAVIS_BUILD_NUMBER"],
"tags": [os.environ['TRAVIS_PYTHON_VERSION'], 'CI'],
"platform": "Windows 10",
"browserName": os.environ['JUPYTER_TEST_BROWSER'],
"version": "latest",
}
if capabilities['browserName'] == 'firefox':
# Attempt to work around issue where browser loses authentication
capabilities['version'] = '57.0'
hub_url = "%s:%s@localhost:4445" % (username, access_key)
print("Connecting remote driver on Sauce Labs")
driver = Remote(desired_capabilities=capabilities,
command_executor="http://%s/wd/hub" % hub_url)
return 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"]
capabilities = {
"tunnel-identifier": os.environ["TRAVIS_JOB_NUMBER"],
"build": os.environ["TRAVIS_BUILD_NUMBER"],
"tags": [os.environ['TRAVIS_PYTHON_VERSION'], 'CI'],
"platform": "Windows 10",
"browserName": os.environ['JUPYTER_TEST_BROWSER'],
"version": "latest",
}
if capabilities['browserName'] == 'firefox':
# Attempt to work around issue where browser loses authentication
capabilities['version'] = '57.0'
hub_url = "%s:%s@localhost:4445" % (username, access_key)
print("Connecting remote driver on Sauce Labs")
driver = Remote(desired_capabilities=capabilities,
command_executor="http://%s/wd/hub" % hub_url)
driver = make_sauce_driver()
elif os.environ.get('JUPYTER_TEST_BROWSER') == 'chrome':
driver = Chrome()
else:
Expand All @@ -93,7 +108,8 @@ def selenium_driver():
# Teardown
driver.quit()

@pytest.fixture

@pytest.fixture(scope='module')
def authenticated_browser(selenium_driver, notebook_server):
selenium_driver.jupyter_server_info = notebook_server
selenium_driver.get("{url}?token={token}".format(**notebook_server))
Expand Down
53 changes: 53 additions & 0 deletions notebook/tests/selenium/quick_selenium.py
@@ -0,0 +1,53 @@
"""Utilities for driving Selenium interactively to develop tests.
These are not used in the tests themselves - rather, the developer writing tests
can use them to experiment with Selenium.
"""
from selenium.webdriver import Firefox

from notebook.tests.selenium.utils import Notebook
from notebook.notebookapp import list_running_servers

class NoServerError(Exception):

def __init__(self, message):
self.message = message

def quick_driver(lab=False):
"""Quickly create a selenium driver pointing at an active noteboook server.
Usage example:
from notebook.tests.selenium.quick_selenium import quick_driver
driver = quick_driver
Note: you need to manually close the driver that opens with driver.quit()
"""
try:
server = list(list_running_servers())[0]
except IndexError as e:
raise NoServerError('You need a server running before you can run '
'this command')
driver = Firefox()
auth_url = '{url}?token={token}'.format(**server)
driver.get(auth_url)

# If this redirects us to a lab page and we don't want that;
# then we need to redirect ourselves to the classic notebook view
if driver.current_url.endswith('/lab') and not lab:
driver.get(driver.current_url.rstrip('lab')+'tree')
return driver


def quick_notebook():
"""Quickly create a new classic notebook in a selenium driver
Usage example:
from notebook.tests.selenium.quick_selenium import quick_notebook
nb = quick_notebook()
Note: you need to manually close the driver that opens with nb.browser.quit()
"""
return Notebook.new_notebook(quick_driver())
8 changes: 1 addition & 7 deletions notebook/tests/selenium/test_dashboard_nav.py
Expand Up @@ -5,6 +5,7 @@
from selenium.webdriver.support import expected_conditions as EC

from notebook.utils import url_path_join
from notebook.tests.selenium.utils import wait_for_selector
pjoin = os.path.join


Expand Down Expand Up @@ -40,7 +41,6 @@ def get_list_items(browser):
'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
Expand All @@ -49,12 +49,6 @@ def only_dir_links(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
Expand Down
43 changes: 43 additions & 0 deletions notebook/tests/selenium/test_markdown.py
@@ -0,0 +1,43 @@
import os

import pytest
from selenium.webdriver.common.keys import Keys

from .utils import wait_for_selector, Notebook

pjoin = os.path.join


@pytest.fixture
def notebook(authenticated_browser):
return Notebook.new_notebook(authenticated_browser)


def get_rendered_contents(nb):
cl = ["text_cell", "render"]
rendered_cells = [cell.find_element_by_class_name("text_cell_render")
for cell in nb.cells
if all([c in cell.get_attribute("class") for c in cl])]
return [x.get_attribute('innerHTML').strip()
for x in rendered_cells
if x is not None]


def test_markdown_cell(notebook):
nb = notebook
cell_text = ["# Foo",
'**Bar**',
'*Baz*',
'```\nx = 1\n```',
'```aaaa\nx = 1\n```',
]
expected_contents = ['<h1 id="Foo">Foo<a class="anchor-link" href="#Foo">¶</a></h1>',
'<p><strong>Bar</strong></p>',
'<p><em>Baz</em></p>',
'<pre><code>x = 1\n</code></pre>',
'<pre><code class="cm-s-ipython language-aaaa">x = 1\n</code></pre>'
]
nb.append(*cell_text, cell_type="markdown")
nb.run_all()
rendered_contents = get_rendered_contents(nb)
assert rendered_contents == expected_contents

0 comments on commit faa0cab

Please sign in to comment.