Commit 8eb88937 authored by Solly Ross's avatar Solly Ross

Support Skipped Tests and Fix JSHint Issues

The test runner now will not break when Mocha skips tests,
and will properly report them.  Additionally, several JSHint
warnings were fixed, and a `--debug` option was added to see
output from the provider.
parent 466a09f0
......@@ -3,7 +3,7 @@ var path = require('path');
var phantom_path = require('phantomjs').path;
var casper_path = path.resolve(__dirname, 'node_modules/casperjs/bin/casperjs');
process.env['PHANTOMJS_EXECUTABLE'] = phantom_path;
process.env.PHANTOMJS_EXECUTABLE = phantom_path;
var casper_opts = {
child: {
transport: 'http',
......@@ -13,7 +13,7 @@ var casper_opts = {
logLevel: 'debug',
verbose: true
}
}
};
var provide_emitter = function(file_paths) {
var spooky = new Spooky(casper_opts, function(err) {
......@@ -29,22 +29,24 @@ var provide_emitter = function(file_paths) {
spooky.then([{ path_ind: path_ind }, function() {
var res_json = {
file_ind: path_ind
}
};
res_json.num_tests = this.evaluate(function() { return document.querySelectorAll('li.test').length });
res_json.num_passes = this.evaluate(function() { return document.querySelectorAll('li.test.pass').length });
res_json.num_fails = this.evaluate(function() { return document.querySelectorAll('li.test.fail').length });
res_json.num_slow = this.evaluate(function() { return document.querySelectorAll('li.test.pass:not(.fast)').length });
res_json.duration = this.evaluate(function() { return document.querySelector('li.duration em').textContent });
res_json.num_tests = this.evaluate(function() { return document.querySelectorAll('li.test').length; });
res_json.num_passes = this.evaluate(function() { return document.querySelectorAll('li.test.pass').length; });
res_json.num_fails = this.evaluate(function() { return document.querySelectorAll('li.test.fail').length; });
res_json.num_slow = this.evaluate(function() { return document.querySelectorAll('li.test.pass:not(.fast):not(.pending)').length; });
res_json.num_skipped = this.evaluate(function () { return document.querySelectorAll('li.test.pending').length; });
res_json.duration = this.evaluate(function() { return document.querySelector('li.duration em').textContent; });
res_json.suites = this.evaluate(function() {
var traverse_node = function(elem) {
var res;
if (elem.classList.contains('suite')) {
var res = {
res = {
type: 'suite',
name: elem.querySelector('h1').textContent,
has_subfailures: elem.querySelectorAll('li.test.fail').length > 0,
}
};
var child_elems = elem.querySelector('ul').children;
res.children = Array.prototype.map.call(child_elems, traverse_node);
......@@ -52,28 +54,35 @@ var provide_emitter = function(file_paths) {
}
else {
var h2_content = elem.querySelector('h2').childNodes;
var res = {
res = {
type: 'test',
text: h2_content[0].textContent,
}
};
if (elem.classList.contains('pass')) {
res.pass = true;
if (elem.classList.contains('pending')) {
res.slow = false;
res.skipped = true;
}
else {
res.slow = !elem.classList.contains('fast');
res.skipped = false;
res.duration = h2_content[1].textContent;
}
}
else {
res.error = elem.querySelector('pre.error').textContent;
}
return res;
}
}
};
var top_suites = document.querySelectorAll('#mocha-report > li.suite');
return Array.prototype.map.call(top_suites, traverse_node);
});
res_json.replay = this.evaluate(function() { return document.querySelector('a.replay').textContent });
res_json.replay = this.evaluate(function() { return document.querySelector('a.replay').textContent; });
this.emit('test_ready', res_json);
}]);
......@@ -82,9 +91,9 @@ var provide_emitter = function(file_paths) {
});
return spooky;
}
};
module.exports = {
provide_emitter: provide_emitter,
name: 'SpookyJS (CapserJS on PhantomJS)'
}
};
......@@ -5,7 +5,7 @@ var path = require('path');
var make_list = function(val) {
return val.split(',');
}
};
program
.option('-t, --tests <testlist>', 'Run the specified html-file-based test(s). \'testlist\' should be a comma-separated list', make_list, [])
......@@ -16,6 +16,7 @@ program
.option('-p, --provider <name>', 'Use the given provider (defaults to "casper"). Currently, may be "casper" or "zombie"', 'casper')
.option('-g, --generate-html', 'Instead of running the tests, just return the path to the generated HTML file, then wait for user interaction to exit (should be used with -i)')
.option('-o, --output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with -i)')
.option('-d, --debug', 'Show debug output (the "console" event) from the provider')
.parse(process.argv);
var file_paths = [];
......@@ -26,13 +27,15 @@ if (program.autoInject) {
temp.track();
var template = {
header: "<html>\n<head>\n<meta charset='utf-8' />\<link rel='stylesheet' href='node_modules/mocha/mocha.css'/>\n</head>\n<body><div id='mocha'></div>",
script_tag: function(p) { return "<script src='" + p + "'></script>" },
header: "<html>\n<head>\n<meta charset='utf-8' />\n<link rel='stylesheet' href='" + path.resolve(__dirname, 'node_modules/mocha/mocha.css') + "'/>\n</head>\n<body><div id='mocha'></div>",
script_tag: function(p) { return "<script src='" + p + "'></script>"; },
footer: "<script>\nmocha.checkLeaks();\nmocha.globals(['navigator', 'create', 'ClientUtils', '__utils__']);\nmocha.run();\n</script>\n</body>\n</html>"
};
template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/chai/chai.js'));
template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/mocha/mocha.js'));
template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/sinon/pkg/sinon.js'));
template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/sinon-chai/lib/sinon-chai.js'));
template.header += "\n<script>mocha.setup('bdd');</script>";
......@@ -137,8 +140,8 @@ if (!program.outputHtml && !program.generateHtml) {
console.log('');
cursor.write(''+test_json.num_tests+' tests run, ')
cursor
.write(''+test_json.num_tests+' tests run, ')
.green()
.write(''+test_json.num_passes+' passed');
if (test_json.num_slow > 0) {
......@@ -157,9 +160,16 @@ if (!program.outputHtml && !program.generateHtml) {
cursor
.red()
.write(''+test_json.num_fails+' failed');
if (test_json.num_skipped > 0) {
cursor
.reset()
.write(', ')
.grey()
.write(''+test_json.num_skipped+' skipped');
}
cursor
.reset()
.write(' -- duration: '+test_json.duration+"\n");
.write(' -- duration: '+test_json.duration+"s\n");
console.log('');
......@@ -168,7 +178,7 @@ if (!program.outputHtml && !program.generateHtml) {
if (node.type == 'suite') {
if (!node.has_subfailures && !program.printAll) return;
if (indentation == 0) {
if (indentation === 0) {
cursor.bold();
console.log(node.name);
console.log(Array(node.name.length+1).join('-'));
......@@ -195,17 +205,25 @@ if (!program.outputHtml && !program.generateHtml) {
cursor.magenta();
console.log('- failed: '+node.text+test_json.replay);
cursor.red();
console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS, we get a stack trace too
console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS where we get a stack trace too
cursor.reset();
console.log('');
}
else if (program.printAll) {
if (node.skipped) {
cursor
.grey()
.write('- skipped: '+node.text);
}
else {
if (node.slow) cursor.yellow();
else cursor.green();
cursor
.write('- pass: '+node.text)
.grey()
.write(' ('+node.duration+') ');
}
/*if (node.slow) cursor.yellow();
else cursor.green();*/
cursor
......@@ -215,23 +233,25 @@ if (!program.outputHtml && !program.generateHtml) {
console.log('');
}
}
}
};
for (var i = 0; i < test_json.suites.length; i++) {
traverse_tree(0, test_json.suites[i]);
}
}
if (test_json.num_fails == 0) {
if (test_json.num_fails === 0) {
cursor.fg.green();
console.log('all tests passed :-)');
cursor.reset();
}
});
/*provider.on('console', function(line) {
//console.log(line);
});*/
if (program.debug) {
provider.on('console', function(line) {
console.log(line);
});
}
/*gprom.finally(function(ph) {
ph.exit();
......
......@@ -18,16 +18,18 @@ var provide_emitter = function(file_paths) {
res_json.num_fails = browser.querySelectorAll('li.test.fail').length;
res_json.num_passes = browser.querySelectorAll('li.test.pass').length;
res_json.num_slow = browser.querySelectorAll('li.test.pass:not(.fast)').length;
res_json.num_skipped = browser.querySelectorAll('li.test.pending').length;
res_json.duration = browser.text('li.duration em');
var traverse_node = function(elem) {
var classList = elem.className.split(' ');
var res;
if (classList.indexOf('suite') > -1) {
var res = {
res = {
type: 'suite',
name: elem.querySelector('h1').textContent,
has_subfailures: elem.querySelectorAll('li.test.fail').length > 0
}
};
var child_elems = elem.querySelector('ul').children;
res.children = Array.prototype.map.call(child_elems, traverse_node);
......@@ -35,23 +37,30 @@ var provide_emitter = function(file_paths) {
}
else {
var h2_content = elem.querySelector('h2').childNodes;
var res = {
res = {
type: 'test',
text: h2_content[0].textContent
}
};
if (classList.indexOf('pass') > -1) {
res.pass = true;
if (classList.indexOf('pending') > -1) {
res.slow = false;
res.skipped = true;
}
else {
res.slow = classList.indexOf('fast') < 0;
res.skipped = false;
res.duration = h2_content[1].textContent;
}
}
else {
res.error = elem.querySelector('pre.error').textContent;
}
return res;
}
}
};
var top_suites = browser.querySelectorAll('#mocha-report > li.suite');
res_json.suites = Array.prototype.map.call(top_suites, traverse_node);
......@@ -65,9 +74,9 @@ var provide_emitter = function(file_paths) {
}, Q(new Browser()));
return emitter;
}
};
module.exports = {
provide_emitter: provide_emitter,
name: 'ZombieJS'
}
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment