diff --git a/.travis.yml b/.travis.yml index 7f018c94a..f29fdcf0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,4 +25,4 @@ install: before_script: - flake8 voila script: - - py.test tests/ + - VOILA_TEST_DEBUG=1 py.test tests/ diff --git a/tests/app/__init__.py b/tests/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/app/conftest.py b/tests/app/conftest.py new file mode 100644 index 000000000..9d8ccc67b --- /dev/null +++ b/tests/app/conftest.py @@ -0,0 +1,44 @@ +import os + +import pytest +import voila.app + + +BASE_DIR = os.path.dirname(__file__) + + +class VoilaTest(voila.app.Voila): + def listen(self): + pass # the ioloop is taken care of by the pytest-tornado framework + + +@pytest.fixture +def voila_config(): + return lambda app: None + + +@pytest.fixture +def voila_args_extra(): + return [] + + +@pytest.fixture +def voila_args(voila_notebook, voila_args_extra): + debug_args = ['--VoilaTest.log_level=DEBUG'] if os.environ.get('VOILA_TEST_DEBUG', False) else [] + return [voila_notebook] + voila_args_extra + debug_args + + +@pytest.fixture +def voila_app(voila_args, voila_config): + voila_app = VoilaTest.instance() + voila_app.initialize(voila_args) + voila_config(voila_app) + voila_app.start() + yield voila_app + voila_app.clear_instance() + +@pytest.fixture +def app(voila_app): + return voila_app.app + + diff --git a/tests/voila_single_notebook_test.py b/tests/app/execute_test.py similarity index 100% rename from tests/voila_single_notebook_test.py rename to tests/app/execute_test.py diff --git a/tests/app/nbextensions_test.py b/tests/app/nbextensions_test.py new file mode 100644 index 000000000..ca47c155d --- /dev/null +++ b/tests/app/nbextensions_test.py @@ -0,0 +1,22 @@ +# tests programmatic config of template sytem +import pytest +import os + +BASE_DIR = os.path.dirname(__file__) + +@pytest.fixture +def voila_config(): + def config(app): + pass + os.environ['JUPYTER_CONFIG_DIR'] = os.path.join(BASE_DIR, '../configs/general') + yield config + del os.environ['JUPYTER_CONFIG_DIR'] + + +@pytest.mark.gen_test +def test_lists_extension(http_client, base_url): + response = yield http_client.fetch(base_url) + assert response.code == 200 + html_text = response.body.decode('utf-8') + assert 'Hi Voila' in html_text + assert 'ipytest/extension.js' in html_text diff --git a/tests/app/serve_directory_test.py b/tests/app/serve_directory_test.py new file mode 100644 index 000000000..4017ce7c0 --- /dev/null +++ b/tests/app/serve_directory_test.py @@ -0,0 +1,15 @@ +# test serving a notebook +import pytest + +@pytest.fixture +def voila_args(notebook_directory, voila_args_extra): + return ['--VoilaTest.root_dir=%r' % notebook_directory, '--VoilaTest.log_level=DEBUG'] + voila_args_extra + + +@pytest.mark.gen_test +def test_hello_world(http_client, print_notebook_url): + print(print_notebook_url) + response = yield http_client.fetch(print_notebook_url) + assert response.code == 200 + assert 'Hi Voila' in response.body.decode('utf-8') + diff --git a/tests/template_cli_test.py b/tests/app/template_cli_test.py similarity index 75% rename from tests/template_cli_test.py rename to tests/app/template_cli_test.py index eb0860a66..0b8a5a3ab 100644 --- a/tests/template_cli_test.py +++ b/tests/app/template_cli_test.py @@ -7,8 +7,8 @@ @pytest.fixture def voila_args_extra(): - path_gridstack = os.path.abspath(os.path.join(BASE_DIR, '../share/jupyter/voila/template/gridstack/nbconvert_templates')) - path_default = os.path.abspath(os.path.join(BASE_DIR, '../share/jupyter/voila/template/default/nbconvert_templates')) + path_gridstack = os.path.abspath(os.path.join(BASE_DIR, '../../share/jupyter/voila/template/gridstack/nbconvert_templates')) + path_default = os.path.abspath(os.path.join(BASE_DIR, '../../share/jupyter/voila/template/default/nbconvert_templates')) return ['--template=None', '--Voila.nbconvert_template_paths=[%r, %r]' % (path_gridstack, path_default)] diff --git a/tests/template_custom_test.py b/tests/app/template_custom_test.py similarity index 75% rename from tests/template_custom_test.py rename to tests/app/template_custom_test.py index 708252cd0..24f27dde9 100644 --- a/tests/template_custom_test.py +++ b/tests/app/template_custom_test.py @@ -13,10 +13,10 @@ def voila_args_extra(): @pytest.fixture def voila_config(): def config(app): - path_gridstack = os.path.abspath(os.path.join(BASE_DIR, '../share/jupyter/voila/template/gridstack/nbconvert_templates')) - path_default = os.path.abspath(os.path.join(BASE_DIR, '../share/jupyter/voila/template/default/nbconvert_templates')) + path_gridstack = os.path.abspath(os.path.join(BASE_DIR, '../../share/jupyter/voila/template/gridstack/nbconvert_templates')) + path_default = os.path.abspath(os.path.join(BASE_DIR, '../../share/jupyter/voila/template/default/nbconvert_templates')) app.nbconvert_template_paths = [path_gridstack, path_default] - path = os.path.abspath(os.path.join(BASE_DIR, '../share/jupyter/voila/template/default/templates')) + path = os.path.abspath(os.path.join(BASE_DIR, '../../share/jupyter/voila/template/default/templates')) app.template_paths = [path] return config diff --git a/tests/template_gridstack_test.py b/tests/app/template_gridstack_test.py similarity index 100% rename from tests/template_gridstack_test.py rename to tests/app/template_gridstack_test.py diff --git a/tests/configs/general/nbconfig/notebook.d/ipytest.json b/tests/configs/general/nbconfig/notebook.d/ipytest.json new file mode 100644 index 000000000..ff6f0f059 --- /dev/null +++ b/tests/configs/general/nbconfig/notebook.d/ipytest.json @@ -0,0 +1,5 @@ +{ + "load_extensions": { + "ipytest/extension": true + } + } \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 4e9c484ae..fc8eb20f1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,49 +1,22 @@ +# fixtures common for app and server import os - import pytest -import voila.app BASE_DIR = os.path.dirname(__file__) -class VoilaTest(voila.app.Voila): - def listen(self): - pass # the ioloop is taken care of by the pytest-tornado framework - - @pytest.fixture -def voila_config(): - return lambda app: None +def notebook_directory(): + return os.path.join(BASE_DIR, 'notebooks') @pytest.fixture -def voila_notebook(): - return os.path.join(BASE_DIR, 'notebooks/print.ipynb') +def print_notebook_url(base_url): + return base_url + "/voila/render/print" @pytest.fixture -def voila_args_extra(): - return [] - - -@pytest.fixture -def voila_args(voila_notebook, voila_args_extra): - debug_args = ['--VoilaTest.log_level=DEBUG'] if os.environ.get('VOILA_TEST_DEBUG', False) else [] - return [voila_notebook] + voila_args_extra + debug_args - - -@pytest.fixture -def voila_app(voila_args, voila_config): - voila_app = VoilaTest.instance() - voila_app.initialize(voila_args) - voila_config(voila_app) - voila_app.start() - return voila_app - - -@pytest.fixture -def app(voila_app): - return voila_app.app - +def voila_notebook(notebook_directory): + return os.path.join(notebook_directory, 'print.ipynb') diff --git a/tests/server/__init__.py b/tests/server/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/server/conftest.py b/tests/server/conftest.py new file mode 100644 index 000000000..6a5f78a9b --- /dev/null +++ b/tests/server/conftest.py @@ -0,0 +1,48 @@ +import os + +import pytest +from jupyter_server.serverapp import ServerApp +from tornado import httpserver + + +BASE_DIR = os.path.dirname(__file__) + + +@pytest.fixture +def jupyter_server_config(): + return lambda app: None + + +@pytest.fixture +def jupyter_server_args_extra(): + return [] + + +@pytest.fixture +def jupyter_server_args(notebook_directory, jupyter_server_args_extra): + debug_args = ['--ServerApp.log_level=DEBUG'] if os.environ.get('VOILA_TEST_DEBUG', False) else [] + default_args = ['--ServerApp.token=""'] + return [notebook_directory] + jupyter_server_args_extra + debug_args + default_args + + +@pytest.fixture +def jupyter_server_app(jupyter_server_args, jupyter_server_config): + jupyter_server_app = ServerApp.instance() + # we monkey patch + old_listen = httpserver.HTTPServer.listen + httpserver.HTTPServer.listen = lambda *x, **y: None + # NOTE: in voila's conftest.py we call config after initialize + jupyter_server_config(jupyter_server_app) + jupyter_server_app.initialize(jupyter_server_args) + yield jupyter_server_app + httpserver.HTTPServer.listen = old_listen + ServerApp.clear_instance() + + + + +@pytest.fixture +def app(jupyter_server_app): + return jupyter_server_app.web_app + + diff --git a/tests/server/execute_test.py b/tests/server/execute_test.py new file mode 100644 index 000000000..e94c5bcb4 --- /dev/null +++ b/tests/server/execute_test.py @@ -0,0 +1,20 @@ +# test basics of voila running a notebook +import pytest +import tornado.web +import tornado.gen +import re +import json + +try: + from unittest import mock +except: + import mock + + +@pytest.mark.gen_test +def test_hello_world(http_client, print_notebook_url): + response = yield http_client.fetch(print_notebook_url) + assert response.code == 200 + html_text = response.body.decode('utf-8') + assert 'Hi Voila' in html_text + assert 'gridstack.css' not in html_text, "gridstack should not be the default" diff --git a/tests/server/nbextensions_test.py b/tests/server/nbextensions_test.py new file mode 100644 index 000000000..f471b6efc --- /dev/null +++ b/tests/server/nbextensions_test.py @@ -0,0 +1,22 @@ +# tests programmatic config of template sytem +import pytest +import os + +BASE_DIR = os.path.dirname(__file__) + +@pytest.fixture +def jupyter_server_config(): + def config(app): + pass + os.environ['JUPYTER_CONFIG_DIR'] = os.path.join(BASE_DIR, 'configs', 'general') + yield config + del os.environ['JUPYTER_CONFIG_DIR'] + +@pytest.mark.xfail(reason='needs to be fixed') +@pytest.mark.gen_test +def test_lists_extension(http_client, print_notebook_url): + response = yield http_client.fetch(print_notebook_url) + assert response.code == 200 + html_text = response.body.decode('utf-8') + assert 'Hi Voila' in html_text + assert 'ipytest/extension.js' in html_text diff --git a/voila/app.py b/voila/app.py index 4c23b5ef4..42369f498 100644 --- a/voila/app.py +++ b/voila/app.py @@ -167,13 +167,10 @@ def _default_root_dir(self): def initialize(self, argv=None): super(Voila, self).initialize(argv) + self.notebook_path = self.notebook_path if self.notebook_path else self.extra_args[0] if len(self.extra_args) == 1 else None signal.signal(signal.SIGTERM, self._handle_signal_stop) - def parse_command_line(self, argv=None): - super(Voila, self).parse_command_line(argv) - def setup_template_dirs(self): - self.notebook_path = self.notebook_path if self.notebook_path else self.extra_args[0] if len(self.extra_args) == 1 else None if self.template: collect_template_paths( self.nbconvert_template_paths, @@ -274,10 +271,16 @@ def start(self): } )) else: + self.log.debug('serving directory: %r', self.root_dir) handlers.extend([ (base_url, VoilaTreeHandler), (url_path_join(base_url, r'/voila/tree' + path_regex), VoilaTreeHandler), - (url_path_join(base_url, r'/voila/render' + path_regex), VoilaHandler, {'strip_sources': self.strip_sources}), + (url_path_join(base_url, r'/voila/render' + path_regex), VoilaHandler, + { + 'strip_sources': self.strip_sources, + 'nbconvert_template_paths': self.nbconvert_template_paths, + 'config': self.config + }), ]) self.app.add_handlers('.*$', handlers) diff --git a/voila/handler.py b/voila/handler.py index ba7789768..513b9e443 100644 --- a/voila/handler.py +++ b/voila/handler.py @@ -38,9 +38,7 @@ def get(self, path=None): load_extensions = notebook_config.get('load_extensions', {}) if "jupyter-js-widgets/extension" in load_extensions: load_extensions["jupyter-js-widgets/extension"] = False - nbextensions = [name for name, enabled in load_extensions.items() if enabled] - else: - nbextensions = [] + nbextensions = [name for name, enabled in load_extensions.items() if enabled] model = self.contents_manager.get(path=notebook_path) if 'content' in model: