Skip to content

Commit faa0cab

Browse files
authored
Merge pull request #3458 from mpacer/selenium_utils
Selenium utils + markdown rendering tests
2 parents dc1eeab + 7266fd5 commit faa0cab

File tree

5 files changed

+355
-27
lines changed

5 files changed

+355
-27
lines changed

notebook/tests/selenium/conftest.py

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
pjoin = os.path.join
1414

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

32+
3133
@pytest.fixture(scope='session')
3234
def notebook_server():
3335
info = {}
@@ -50,10 +52,11 @@ def notebook_server():
5052
# run with a base URL that would be escaped,
5153
# to test that we don't double-escape URLs
5254
'--NotebookApp.base_url=/a@b/',
53-
]
55+
]
5456
print("command=", command)
5557
proc = info['popen'] = Popen(command, cwd=nbdir, env=env)
56-
info_file_path = pjoin(td, 'jupyter_runtime', 'nbserver-%i.json' % proc.pid)
58+
info_file_path = pjoin(td, 'jupyter_runtime',
59+
'nbserver-%i.json' % proc.pid)
5760
info.update(_wait_for_server(proc, info_file_path))
5861

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

69+
70+
def make_sauce_driver():
71+
"""This function helps travis create a driver on Sauce Labs.
72+
73+
This function will err if used without specifying the variables expected
74+
in that context.
75+
"""
76+
77+
username = os.environ["SAUCE_USERNAME"]
78+
access_key = os.environ["SAUCE_ACCESS_KEY"]
79+
capabilities = {
80+
"tunnel-identifier": os.environ["TRAVIS_JOB_NUMBER"],
81+
"build": os.environ["TRAVIS_BUILD_NUMBER"],
82+
"tags": [os.environ['TRAVIS_PYTHON_VERSION'], 'CI'],
83+
"platform": "Windows 10",
84+
"browserName": os.environ['JUPYTER_TEST_BROWSER'],
85+
"version": "latest",
86+
}
87+
if capabilities['browserName'] == 'firefox':
88+
# Attempt to work around issue where browser loses authentication
89+
capabilities['version'] = '57.0'
90+
hub_url = "%s:%s@localhost:4445" % (username, access_key)
91+
print("Connecting remote driver on Sauce Labs")
92+
driver = Remote(desired_capabilities=capabilities,
93+
command_executor="http://%s/wd/hub" % hub_url)
94+
return driver
95+
96+
6697
@pytest.fixture(scope='session')
6798
def selenium_driver():
6899
if os.environ.get('SAUCE_USERNAME'):
69-
username = os.environ["SAUCE_USERNAME"]
70-
access_key = os.environ["SAUCE_ACCESS_KEY"]
71-
capabilities = {
72-
"tunnel-identifier": os.environ["TRAVIS_JOB_NUMBER"],
73-
"build": os.environ["TRAVIS_BUILD_NUMBER"],
74-
"tags": [os.environ['TRAVIS_PYTHON_VERSION'], 'CI'],
75-
"platform": "Windows 10",
76-
"browserName": os.environ['JUPYTER_TEST_BROWSER'],
77-
"version": "latest",
78-
}
79-
if capabilities['browserName'] == 'firefox':
80-
# Attempt to work around issue where browser loses authentication
81-
capabilities['version'] = '57.0'
82-
hub_url = "%s:%s@localhost:4445" % (username, access_key)
83-
print("Connecting remote driver on Sauce Labs")
84-
driver = Remote(desired_capabilities=capabilities,
85-
command_executor="http://%s/wd/hub" % hub_url)
100+
driver = make_sauce_driver()
86101
elif os.environ.get('JUPYTER_TEST_BROWSER') == 'chrome':
87102
driver = Chrome()
88103
else:
@@ -93,7 +108,8 @@ def selenium_driver():
93108
# Teardown
94109
driver.quit()
95110

96-
@pytest.fixture
111+
112+
@pytest.fixture(scope='module')
97113
def authenticated_browser(selenium_driver, notebook_server):
98114
selenium_driver.jupyter_server_info = notebook_server
99115
selenium_driver.get("{url}?token={token}".format(**notebook_server))
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Utilities for driving Selenium interactively to develop tests.
2+
3+
These are not used in the tests themselves - rather, the developer writing tests
4+
can use them to experiment with Selenium.
5+
"""
6+
from selenium.webdriver import Firefox
7+
8+
from notebook.tests.selenium.utils import Notebook
9+
from notebook.notebookapp import list_running_servers
10+
11+
class NoServerError(Exception):
12+
13+
def __init__(self, message):
14+
self.message = message
15+
16+
def quick_driver(lab=False):
17+
"""Quickly create a selenium driver pointing at an active noteboook server.
18+
19+
Usage example:
20+
21+
from notebook.tests.selenium.quick_selenium import quick_driver
22+
driver = quick_driver
23+
24+
Note: you need to manually close the driver that opens with driver.quit()
25+
"""
26+
try:
27+
server = list(list_running_servers())[0]
28+
except IndexError as e:
29+
raise NoServerError('You need a server running before you can run '
30+
'this command')
31+
driver = Firefox()
32+
auth_url = '{url}?token={token}'.format(**server)
33+
driver.get(auth_url)
34+
35+
# If this redirects us to a lab page and we don't want that;
36+
# then we need to redirect ourselves to the classic notebook view
37+
if driver.current_url.endswith('/lab') and not lab:
38+
driver.get(driver.current_url.rstrip('lab')+'tree')
39+
return driver
40+
41+
42+
def quick_notebook():
43+
"""Quickly create a new classic notebook in a selenium driver
44+
45+
46+
Usage example:
47+
48+
from notebook.tests.selenium.quick_selenium import quick_notebook
49+
nb = quick_notebook()
50+
51+
Note: you need to manually close the driver that opens with nb.browser.quit()
52+
"""
53+
return Notebook.new_notebook(quick_driver())

notebook/tests/selenium/test_dashboard_nav.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from selenium.webdriver.support import expected_conditions as EC
66

77
from notebook.utils import url_path_join
8+
from notebook.tests.selenium.utils import wait_for_selector
89
pjoin = os.path.join
910

1011

@@ -40,7 +41,6 @@ def get_list_items(browser):
4041
'element': a,
4142
} for a in browser.find_elements_by_class_name('item_link')]
4243

43-
4444
def only_dir_links(browser):
4545
"""Return only links that point at other directories in the tree
4646
@@ -49,12 +49,6 @@ def only_dir_links(browser):
4949
return [i for i in items
5050
if url_in_tree(browser, i['link']) and i['label'] != '..']
5151

52-
53-
def wait_for_selector(browser, selector, timeout=10):
54-
wait = WebDriverWait(browser, timeout)
55-
return wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector)))
56-
57-
5852
def test_items(authenticated_browser):
5953
visited_dict = {}
6054
# Going down the tree to collect links
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import os
2+
3+
import pytest
4+
from selenium.webdriver.common.keys import Keys
5+
6+
from .utils import wait_for_selector, Notebook
7+
8+
pjoin = os.path.join
9+
10+
11+
@pytest.fixture
12+
def notebook(authenticated_browser):
13+
return Notebook.new_notebook(authenticated_browser)
14+
15+
16+
def get_rendered_contents(nb):
17+
cl = ["text_cell", "render"]
18+
rendered_cells = [cell.find_element_by_class_name("text_cell_render")
19+
for cell in nb.cells
20+
if all([c in cell.get_attribute("class") for c in cl])]
21+
return [x.get_attribute('innerHTML').strip()
22+
for x in rendered_cells
23+
if x is not None]
24+
25+
26+
def test_markdown_cell(notebook):
27+
nb = notebook
28+
cell_text = ["# Foo",
29+
'**Bar**',
30+
'*Baz*',
31+
'```\nx = 1\n```',
32+
'```aaaa\nx = 1\n```',
33+
]
34+
expected_contents = ['<h1 id="Foo">Foo<a class="anchor-link" href="#Foo">¶</a></h1>',
35+
'<p><strong>Bar</strong></p>',
36+
'<p><em>Baz</em></p>',
37+
'<pre><code>x = 1\n</code></pre>',
38+
'<pre><code class="cm-s-ipython language-aaaa">x = 1\n</code></pre>'
39+
]
40+
nb.append(*cell_text, cell_type="markdown")
41+
nb.run_all()
42+
rendered_contents = get_rendered_contents(nb)
43+
assert rendered_contents == expected_contents

0 commit comments

Comments
 (0)