Skip to content

Commit aa9c977

Browse files
takluyvergnestor
authored andcommitted
Testing with Selenium & Sauce labs (#3321)
* Initial selenium test * Try configuring Travis to run selenium tests on Sauce * Encryption key needs to be for my account, not jupyter * Install selenium on Travis * Get more data from server info file * Set cwd when launching notebook server Will this help on Travis? * Use JUPYTER_TEST_BROWSER=chrome to test with Chrome * Debugging test * Separate fixtures into conftest.py * Try with --Cls.a=b option syntax * Try using sauce labs directly, not through Travis proxy * Back to using proxy, with http instead of https Idea from https://stackoverflow.com/questions/48236104/ssl-errors-using- sauce-labs-in-travis-ci-with-selenium-webriver-tests-django-pr * Specify browserName in desired_capabilities for Sauce * Try connecting to Sauce for only some jobs in matrix * Exclude selenium tests from regular test run * Remove redundant JS test for dashboard navigation (converted to Selenium) * Re-enable other tests * Exclude selenium tests on Appveyor * Later browser versions are available on Windows * Try running tests with Firefox 57 instead of 58 * Try running with local Firefox on Travis * Install geckodriver for Selenium tests * Untar the right version of geckodriver * Try stepping back one version of Firefox again
1 parent 4285574 commit aa9c977

File tree

7 files changed

+165
-54
lines changed

7 files changed

+165
-54
lines changed

.travis.yml

+21-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ python:
1111

1212
sudo: required
1313

14+
1415
env:
1516
global:
1617
- PATH=$TRAVIS_BUILD_DIR/pandoc:$PATH
@@ -19,8 +20,6 @@ env:
1920
- GROUP=python
2021
- GROUP=js/base
2122
- GROUP=js/services
22-
- GROUP=js/tree
23-
- GROUP=docs
2423

2524
before_install:
2625
- pip install --upgrade pip
@@ -40,6 +39,15 @@ before_install:
4039
if [[ $GROUP == docs ]]; then
4140
pip install -r docs/doc-requirements.txt
4241
fi
42+
- |
43+
if [[ $GROUP == selenium ]]; then
44+
pip install selenium
45+
# Install Webdriver backend for Firefox:
46+
wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz
47+
mkdir geckodriver
48+
tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C geckodriver
49+
export PATH=$PATH:$PWD/geckodriver
50+
fi
4351
4452
install:
4553
- pip install -f travis-wheels/wheelhouse file://$PWD#egg=notebook[test]
@@ -59,7 +67,8 @@ script:
5967
true
6068
fi
6169
- 'if [[ $GROUP == js* ]]; then travis_retry python -m notebook.jstest ${GROUP:3}; fi'
62-
- 'if [[ $GROUP == python ]]; then nosetests -v --with-coverage --cover-package=notebook notebook; fi'
70+
- 'if [[ $GROUP == python ]]; then nosetests -v --exclude-dir notebook/tests/selenium --with-coverage --cover-package=notebook notebook; fi'
71+
- 'if [[ $GROUP == selenium ]]; then py.test -sv notebook/tests/selenium; fi'
6372
- |
6473
if [[ $GROUP == docs ]]; then
6574
EXIT_STATUS=0
@@ -72,12 +81,19 @@ script:
7281
7382
matrix:
7483
include:
84+
- python: 3.6
85+
env:
86+
- GROUP=selenium
87+
- JUPYTER_TEST_BROWSER=firefox
88+
- MOZ_HEADLESS=1
89+
addons:
90+
firefox: 57.0
91+
7592
- python: 3.4
7693
env: GROUP=python
7794
- python: 3.5
7895
env: GROUP=python
79-
exclude:
80-
- python: 2.7
96+
- python: 3.6
8197
env: GROUP=docs
8298

8399
after_success:

appveyor.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ install:
2323
- cmd: pip install .[test]
2424

2525
test_script:
26-
- nosetests -v notebook
26+
- nosetests -v notebook --exclude-dir notebook\tests\selenium

notebook/tests/selenium/__init__.py

Whitespace-only changes.

notebook/tests/selenium/conftest.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import json
2+
import os
3+
import pytest
4+
import requests
5+
from subprocess import Popen
6+
import sys
7+
from testpath.tempdir import TemporaryDirectory
8+
import time
9+
from urllib.parse import urljoin
10+
11+
from selenium.webdriver import Firefox, Remote, Chrome
12+
13+
pjoin = os.path.join
14+
15+
def _wait_for_server(proc, info_file_path):
16+
"""Wait 30 seconds for the notebook server to start"""
17+
for i in range(300):
18+
if proc.poll() is not None:
19+
raise RuntimeError("Notebook server failed to start")
20+
if os.path.exists(info_file_path):
21+
try:
22+
with open(info_file_path) as f:
23+
return json.load(f)
24+
except ValueError:
25+
# If the server is halfway through writing the file, we may
26+
# get invalid JSON; it should be ready next iteration.
27+
pass
28+
time.sleep(0.1)
29+
raise RuntimeError("Didn't find %s in 30 seconds", info_file_path)
30+
31+
@pytest.fixture(scope='session')
32+
def notebook_server():
33+
info = {}
34+
with TemporaryDirectory() as td:
35+
nbdir = info['nbdir'] = pjoin(td, 'notebooks')
36+
os.makedirs(pjoin(nbdir, u'sub ∂ir1', u'sub ∂ir 1a'))
37+
os.makedirs(pjoin(nbdir, u'sub ∂ir2', u'sub ∂ir 1b'))
38+
39+
info['extra_env'] = {
40+
'JUPYTER_CONFIG_DIR': pjoin(td, 'jupyter_config'),
41+
'JUPYTER_RUNTIME_DIR': pjoin(td, 'jupyter_runtime'),
42+
'IPYTHONDIR': pjoin(td, 'ipython'),
43+
}
44+
env = os.environ.copy()
45+
env.update(info['extra_env'])
46+
47+
command = [sys.executable, '-m', 'notebook',
48+
'--no-browser',
49+
'--notebook-dir', nbdir,
50+
# run with a base URL that would be escaped,
51+
# to test that we don't double-escape URLs
52+
'--NotebookApp.base_url=/a@b/',
53+
]
54+
print("command=", command)
55+
proc = info['popen'] = Popen(command, cwd=nbdir, env=env)
56+
info_file_path = pjoin(td, 'jupyter_runtime', 'nbserver-%i.json' % proc.pid)
57+
info.update(_wait_for_server(proc, info_file_path))
58+
59+
print("Notebook server info:", info)
60+
yield info
61+
62+
# Shut the server down
63+
requests.post(urljoin(info['url'], 'api/shutdown'),
64+
headers={'Authorization': 'token '+info['token']})
65+
66+
67+
def _get_selenium_driver():
68+
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+
return Remote(desired_capabilities=capabilities,
85+
command_executor="http://%s/wd/hub" % hub_url)
86+
elif os.environ.get('JUPYTER_TEST_BROWSER') == 'chrome':
87+
return Chrome()
88+
else:
89+
return Firefox()
90+
91+
@pytest.fixture
92+
def browser(notebook_server):
93+
b = _get_selenium_driver()
94+
b.get("{url}?token={token}".format(**notebook_server))
95+
yield b
96+
b.quit()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
3+
from selenium.webdriver.common.by import By
4+
from selenium.webdriver.support.ui import WebDriverWait
5+
from selenium.webdriver.support import expected_conditions as EC
6+
7+
pjoin = os.path.join
8+
9+
def get_list_items(browser):
10+
return [{
11+
'link': a.get_attribute('href'),
12+
'label': a.find_element_by_class_name('item_name').text,
13+
} for a in browser.find_elements_by_class_name('item_link')]
14+
15+
16+
def wait_for_selector(browser, selector, timeout=10):
17+
wait = WebDriverWait(browser, timeout)
18+
return wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector)))
19+
20+
21+
22+
def test_items(browser, visited=None):
23+
tree_root_url = browser.current_url
24+
if visited is None:
25+
visited = set()
26+
27+
wait_for_selector(browser, '.item_link')
28+
items = get_list_items(browser)
29+
print(browser.current_url, len(items))
30+
for item in items:
31+
print(item)
32+
url = item['link']
33+
if url.startswith(tree_root_url):
34+
print("Going to", url)
35+
if url in visited:
36+
continue
37+
visited.add(url)
38+
browser.get(url)
39+
wait_for_selector(browser, '.item_link')
40+
assert browser.current_url == url
41+
42+
test_items(browser, visited)
43+
#browser.back()
44+
45+
print()

notebook/tests/tree/dashboard_nav.js

-47
This file was deleted.

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@
9191
],
9292
extras_require = {
9393
'test:python_version == "2.7"': ['mock'],
94-
'test': ['nose', 'coverage', 'requests', 'nose_warnings_filters', 'nbval'],
94+
'test': ['nose', 'coverage', 'requests', 'nose_warnings_filters',
95+
'nbval', 'nose-exclude'],
9596
'test:sys_platform == "win32"': ['nose-exclude'],
9697
},
9798
entry_points = {

0 commit comments

Comments
 (0)