From f3ebe117679fc0fe76acfdbbfeb04cae66a01e78 2014-06-04 19:10:29 From: Jonathan Frederic <jdfreder@calpoly.edu> Date: 2014-06-04 19:10:29 Subject: [PATCH] Adde slimerjs support to JS tests This commit contains 16 more, squashed commits: Added slimerjs flag Fixed some bugs with flag code Figured out how to add arg correctly Cleanup Improvements to the test framework for FF Log to see if slimmer is actually running Added print in controller to debug Added full logging to casperjs Remove the special logging logic since it was caussing a failure remove notebook.dirty = false line in favor of overwritting onbeforeunload. Capture output for slimerjs Fixed iptestcontroller rebase issues Fixed rebase issues. Wait for notebook to load completely before testing Fixed stdout capture for slimerjs tests. Clean-up comments in util.js Added slimerjs to Travis Fixed indent .travis.yml Comment out slimerjslauncher env var. Removed zmq flag which doesn't work there anyways, it was added by me in a recent commit Fixed travis yaml, broken because of rebase --- diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index dad8609..22287ce 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -1,7 +1,6 @@ // // Utility functions for the HTML notebook's CasperJS tests. // - casper.get_notebook_server = function () { // Get the URL of a notebook server on which to run tests. port = casper.cli.get("port"); @@ -32,6 +31,15 @@ casper.open_new_notebook = function () { IPython._status = 'busy'; }); }); + + // Because of the asynchronous nature of SlimerJS (Gecko), we need to make + // sure the notebook has actually been loaded into the IPython namespace + // before running any tests. + this.waitFor(function() { + return this.evaluate(function () { + return IPython.notebook; + }); + }); }; casper.kernel_running = function kernel_running() { @@ -411,9 +419,30 @@ casper.cell_has_class = function(index, classes) { casper.notebook_test = function(test) { // Wrap a notebook test to reduce boilerplate. + // + // If you want to read parameters from the commandline, use the following + // (i.e. value=): + // if (casper.cli.options.value) { + // casper.exit(1); + // } this.open_new_notebook(); - this.then(test); + // Echo whether or not we are running this test using SlimerJS + if (this.evaluate(function(){ + return typeof InstallTrigger !== 'undefined'; // Firefox 1.0+ + })) { console.log('This test is running in SlimerJS.'); } + + // Make sure to remove the onbeforeunload callback. This callback is + // responsable for the "Are you sure you want to quit?" type messages. + // PhantomJS ignores these prompts, SlimerJS does not which causes hangs. + this.then(function(){ + this.evaluate(function(){ + window.onbeforeunload = function(){}; + }); + }); + + this.then(test); + // Kill the kernel and delete the notebook. this.shutdown_current_kernel(); // This is still broken but shouldn't be a problem for now. diff --git a/IPython/html/tests/widgets/widget.js b/IPython/html/tests/widgets/widget.js index 3067ab6..5eb8d5b 100644 --- a/IPython/html/tests/widgets/widget.js +++ b/IPython/html/tests/widgets/widget.js @@ -1,9 +1,15 @@ var xor = function (a, b) {return !a ^ !b;}; -var isArray = function (a) {return toString.call(a) === "[object Array]" || toString.call(a) === "[object RuntimeArray]";}; +var isArray = function (a) { + try { + return Object.toString.call(a) === "[object Array]" || Object.toString.call(a) === "[object RuntimeArray]"; + } catch (e) { + return Array.isArray(a); + } +}; var recursive_compare = function(a, b) { // Recursively compare two objects. var same = true; - same = same && !xor(a instanceof Object, b instanceof Object); + same = same && !xor(a instanceof Object || typeof a == 'object', b instanceof Object || typeof b == 'object'); same = same && !xor(isArray(a), isArray(b)); if (same) { diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 957b8a3..bb03e38 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -148,6 +148,8 @@ have['jinja2'] = test_for('jinja2') have['requests'] = test_for('requests') have['sphinx'] = test_for('sphinx') have['casperjs'] = is_cmd_found('casperjs') +have['phantomjs'] = is_cmd_found('phantomjs') +have['slimerjs'] = is_cmd_found('slimerjs') min_zmq = (2,1,11) diff --git a/IPython/testing/iptestcontroller.py b/IPython/testing/iptestcontroller.py index ee3e0e7..5b48b0a 100644 --- a/IPython/testing/iptestcontroller.py +++ b/IPython/testing/iptestcontroller.py @@ -20,12 +20,14 @@ import signal import sys import subprocess import time +import re from .iptest import have, test_group_names as py_test_group_names, test_sections, StreamCapturer from IPython.utils.path import compress_user from IPython.utils.py3compat import bytes_to_str from IPython.utils.sysinfo import get_sys_info from IPython.utils.tempdir import TemporaryDirectory +from IPython.nbconvert.filters.ansi import strip_ansi try: # Python >= 3.3 @@ -214,15 +216,17 @@ def all_js_groups(): class JSController(TestController): """Run CasperJS tests """ requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3'] - def __init__(self, section, enabled=True): + def __init__(self, section, enabled=True, engine='phantomjs'): """Create new test runner.""" TestController.__init__(self) + self.engine = engine self.section = section self.enabled = enabled + self.slimer_failure = re.compile('^FAIL.*', flags=re.MULTILINE) js_test_dir = get_js_test_dir() includes = '--includes=' + os.path.join(js_test_dir,'util.js') test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):]) - self.cmd = ['casperjs', 'test', includes, test_cases] + self.cmd = ['casperjs', 'test', includes, test_cases, '--engine=%s' % self.engine] def setup(self): self.ipydir = TemporaryDirectory() @@ -240,13 +244,31 @@ class JSController(TestController): else: # don't launch tests if the server didn't start self.cmd = [sys.executable, '-c', 'raise SystemExit(1)'] + + def launch(self, buffer_output): + # If the engine is SlimerJS, we need to buffer the output because + # SlimerJS does not support exit codes, therefor CasperJS always returns + # 0 which is a false positive. + buffer_output = (self.engine == 'slimerjs') or buffer_output + super(JSController, self).launch(buffer_output=buffer_output) + + def wait(self, *pargs, **kwargs): + """Wait for the JSController to finish""" + ret = super(JSController, self).wait(*pargs, **kwargs) + # If this is a SlimerJS controller, echo the captured output. + if self.engine == 'slimerjs': + print(self.stdout) + # Return True if a failure occured. + return self.slimer_failure.search(strip_ansi(self.stdout)) + else: + return ret def print_extra_info(self): print("Running tests with notebook directory %r" % self.nbdir.name) @property def will_run(self): - return self.enabled and all(have[a] for a in self.requirements) + return self.enabled and all(have[a] for a in self.requirements + [self.engine]) def _init_server(self): "Start the notebook server in a separate process" @@ -281,7 +303,7 @@ class JSController(TestController): # get invalid JSON; it should be ready next iteration. pass else: - return + return time.sleep(0.1) print("Notebook server-info file never arrived: %s" % self.server_info_file, file=sys.stderr @@ -350,7 +372,8 @@ def prepare_controllers(options): else: js_testgroups = all_js_groups() - c_js = [JSController(name) for name in js_testgroups] + engine = 'phantomjs' if have['phantomjs'] and not options.slimerjs else 'slimerjs' + c_js = [JSController(name, engine=engine) for name in js_testgroups] c_py = [PyTestController(name, options) for name in py_testgroups] controllers = c_py + c_js @@ -455,6 +478,9 @@ def run_iptestall(options): Include slow tests, like IPython.parallel. By default, these tests aren't run. + slimerjs : bool + Use slimerjs if it's installed instead of phantomjs for casperjs tests. + xunit : bool Produce Xunit XML output. This is written to multiple foo.xunit.xml files. @@ -581,6 +607,8 @@ argparser.add_argument('testgroups', nargs='*', 'all tests.') argparser.add_argument('--all', action='store_true', help='Include slow tests not run by default.') +argparser.add_argument('--slimerjs', action='store_true', + help="Use slimerjs if it's installed instead of phantomjs for casperjs tests.") argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int, help='Run test sections in parallel. This starts as many ' 'processes as you have cores, or you can specify a number.')