forked from jupyterlab/jupyterlab
/
browser_check.py
130 lines (104 loc) · 3.52 KB
/
browser_check.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# -*- coding: utf-8 -*-
"""
This module is meant to run JupyterLab in a headless browser, making sure
the application launches and starts up without errors.
"""
from concurrent.futures import ThreadPoolExecutor
import logging
from os import path as osp
import os
import shutil
import sys
import subprocess
from tornado.ioloop import IOLoop
from notebook.notebookapp import flags, aliases
from traitlets import Bool
from .labapp import LabApp, get_app_dir
from .tests.test_app import TestEnv
here = osp.abspath(osp.dirname(__file__))
test_flags = dict(flags)
test_flags['core-mode'] = (
{'BrowserApp': {'core_mode': True}},
"Start the app in core mode."
)
test_flags['dev-mode'] = (
{'BrowserApp': {'dev_mode': True}},
"Start the app in dev mode."
)
test_aliases = dict(aliases)
test_aliases['app-dir'] = 'BrowserApp.app_dir'
class LogErrorHandler(logging.Handler):
"""A handler that exits with 1 on a logged error."""
def __init__(self):
super().__init__(level=logging.ERROR)
self.errored = False
def filter(self, record):
# known startup error message
if 'paste' in record.msg:
return
return super().filter(record)
def emit(self, record):
print(record.msg, file=sys.stderr)
self.errored = True
def run_test(app, func):
"""Run a test against the application.
func is a function that accepts an app url as a parameter and returns a result.
"""
handler = LogErrorHandler()
env_patch = TestEnv()
env_patch.start()
def finished(future):
try:
result = future.result()
except Exception as e:
app.log.error(str(e))
app.log.info('Stopping server...')
app.stop()
if handler.errored:
app.log.critical('Exiting with 1 due to errors')
result = 1
elif result != 0:
app.log.critical('Exiting with %s due to errors' % result)
else:
app.log.info('Exiting normally')
result = 0
app.http_server.stop()
app.io_loop.stop()
env_patch.stop()
try:
os._exit(result)
except Exception as e:
self.log.error(str(e))
os._exit(1)
app.log.addHandler(handler)
pool = ThreadPoolExecutor()
future = pool.submit(func, app.display_url)
IOLoop.current().add_future(future, finished)
class BrowserApp(LabApp):
"""An app the launches JupyterLab and waits for it to start up, checking for
JS console errors, JS errors, and Python logged errors.
"""
open_browser = Bool(False)
base_url = '/foo/'
ip = '127.0.0.1'
flags = test_flags
aliases = test_aliases
def start(self):
web_app = self.web_app
web_app.settings.setdefault('page_config_data', dict())
web_app.settings['page_config_data']['browserTest'] = True
web_app.settings['page_config_data']['buildAvailable'] = False
run_test(self, run_browser)
super().start()
def run_browser(url):
"""Run the browser test and return an exit code.
"""
target = osp.join(get_app_dir(), 'browser_test')
if not osp.exists(osp.join(target, 'node_modules')):
os.makedirs(target)
subprocess.call(["jlpm"], cwd=target)
subprocess.call(["jlpm", "add", "puppeteer"], cwd=target)
shutil.copy(osp.join(here, 'chrome-test.js'), osp.join(target, 'chrome-test.js'))
return subprocess.check_call(["node", "chrome-test.js", url], cwd=target)
if __name__ == '__main__':
BrowserApp.launch_instance()