Merge pull request #322 from DirectXMan12/master
Support Running Mocha Tests from the Console
This commit is contained in:
commit
e0dc102e5b
|
@ -0,0 +1,90 @@
|
|||
var Spooky = require('spooky');
|
||||
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;
|
||||
var casper_opts = {
|
||||
child: {
|
||||
transport: 'http',
|
||||
command: casper_path
|
||||
},
|
||||
casper: {
|
||||
logLevel: 'debug',
|
||||
verbose: true
|
||||
}
|
||||
}
|
||||
|
||||
var provide_emitter = function(file_paths) {
|
||||
var spooky = new Spooky(casper_opts, function(err) {
|
||||
if (err) {
|
||||
if (err.stack) console.warn(err.stack);
|
||||
else console.warn(err);
|
||||
return;
|
||||
}
|
||||
spooky.start('about:blank');
|
||||
|
||||
file_paths.forEach(function(file_path, path_ind) {
|
||||
spooky.thenOpen('file://'+file_path);
|
||||
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.suites = this.evaluate(function() {
|
||||
var traverse_node = function(elem) {
|
||||
if (elem.classList.contains('suite')) {
|
||||
var 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);
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
var h2_content = elem.querySelector('h2').childNodes;
|
||||
var res = {
|
||||
type: 'test',
|
||||
text: h2_content[0].textContent,
|
||||
}
|
||||
|
||||
if (elem.classList.contains('pass')) {
|
||||
res.pass = true;
|
||||
res.slow = !elem.classList.contains('fast');
|
||||
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 });
|
||||
|
||||
this.emit('test_ready', res_json);
|
||||
}]);
|
||||
});
|
||||
spooky.run();
|
||||
});
|
||||
|
||||
return spooky;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
provide_emitter: provide_emitter,
|
||||
name: 'SpookyJS (CapserJS on PhantomJS)'
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
#!/usr/bin/env node
|
||||
var ansi = require('ansi');
|
||||
var program = require('commander');
|
||||
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, [])
|
||||
.option('-a, --print-all', 'Print all tests, not just the failures')
|
||||
.option('--disable-color', 'Explicitly disable color')
|
||||
.option('-c, --color', 'Explicitly enable color (default is to use color when not outputting to a pipe)')
|
||||
.option('-i, --auto-inject <includefiles>', 'Treat the test list as a set of mocha JS files, and automatically generate HTML files with which to test test. \'includefiles\' should be a comma-separated list of paths to javascript files to include in each of the generated HTML files', make_list, null)
|
||||
.option('-p, --provider <name>', 'Use the given provider (defaults to "casper"). Currently, may be "casper" or "zombie"', 'casper')
|
||||
.parse(process.argv);
|
||||
|
||||
var file_paths = [];
|
||||
|
||||
if (program.autoInject) {
|
||||
var temp = require('temp');
|
||||
var fs = require('fs');
|
||||
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>" },
|
||||
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<script>mocha.setup('bdd');</script>";
|
||||
|
||||
|
||||
template.header = program.autoInject.reduce(function(acc, sn) {
|
||||
return acc + "\n" + template.script_tag(path.resolve(process.cwd(), sn));
|
||||
}, template.header);
|
||||
|
||||
file_paths = program.tests.map(function(jsn, ind) {
|
||||
var templ = template.header;
|
||||
templ += "\n";
|
||||
templ += template.script_tag(path.resolve(process.cwd(), jsn));
|
||||
templ += template.footer;
|
||||
|
||||
var tempfile = temp.openSync({ prefix: 'novnc-zombie-inject-', suffix: '-file_num-'+ind+'.html' });
|
||||
fs.writeSync(tempfile.fd, templ);
|
||||
fs.closeSync(tempfile.fd);
|
||||
return tempfile.path;
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
file_paths = program.tests.map(function(fn) {
|
||||
return path.resolve(process.cwd(), fn);
|
||||
});
|
||||
}
|
||||
|
||||
var failure_count = 0;
|
||||
|
||||
var use_ansi = false;
|
||||
if (program.color) use_ansi = true;
|
||||
else if (program.disableColor) use_ansi = false;
|
||||
else if (process.stdout.isTTY) use_ansi = true;
|
||||
|
||||
var cursor = ansi(process.stdout, { enabled: use_ansi });
|
||||
|
||||
var prov = require(path.resolve(__dirname, 'run_from_console.'+program.provider+'.js'));
|
||||
|
||||
cursor
|
||||
.write("Running tests ")
|
||||
.bold()
|
||||
.write(program.tests.join(', '))
|
||||
.reset()
|
||||
.grey()
|
||||
.write(' using provider '+prov.name)
|
||||
.reset()
|
||||
.write("\n");
|
||||
//console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name);
|
||||
|
||||
var provider = prov.provide_emitter(file_paths);
|
||||
provider.on('test_ready', function(test_json) {
|
||||
console.log('');
|
||||
|
||||
filename = program.tests[test_json.file_ind];
|
||||
|
||||
cursor.bold();
|
||||
console.log('Results for %s:', filename);
|
||||
console.log(Array('Results for :'.length+filename.length+1).join('='));
|
||||
cursor.reset();
|
||||
|
||||
console.log('');
|
||||
|
||||
cursor.write(''+test_json.num_tests+' tests run, ')
|
||||
cursor
|
||||
.green()
|
||||
.write(''+test_json.num_passes+' passed');
|
||||
if (test_json.num_slow > 0) {
|
||||
cursor
|
||||
.reset()
|
||||
.write(' (');
|
||||
cursor
|
||||
.yellow()
|
||||
.write(''+test_json.num_slow+' slow')
|
||||
.reset()
|
||||
.write(')');
|
||||
}
|
||||
cursor
|
||||
.reset()
|
||||
.write(', ');
|
||||
cursor
|
||||
.red()
|
||||
.write(''+test_json.num_fails+' failed');
|
||||
cursor
|
||||
.reset()
|
||||
.write(' -- duration: '+test_json.duration+"\n");
|
||||
|
||||
console.log('');
|
||||
|
||||
if (test_json.num_fails > 0 || program.printAll) {
|
||||
var traverse_tree = function(indentation, node) {
|
||||
if (node.type == 'suite') {
|
||||
if (!node.has_subfailures && !program.printAll) return;
|
||||
|
||||
if (indentation == 0) {
|
||||
cursor.bold();
|
||||
console.log(node.name);
|
||||
console.log(Array(node.name.length+1).join('-'));
|
||||
cursor.reset();
|
||||
}
|
||||
else {
|
||||
cursor
|
||||
.write(Array(indentation+3).join('#'))
|
||||
.bold()
|
||||
.write(' '+node.name+' ')
|
||||
.reset()
|
||||
.write(Array(indentation+3).join('#'))
|
||||
.write("\n");
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
traverse_tree(indentation+1, node.children[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!node.pass) {
|
||||
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
|
||||
cursor.reset();
|
||||
console.log('');
|
||||
}
|
||||
else if (program.printAll) {
|
||||
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
|
||||
//.write(test_json.replay)
|
||||
.reset()
|
||||
.write("\n");
|
||||
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) {
|
||||
cursor.fg.green();
|
||||
console.log('all tests passed :-)');
|
||||
cursor.reset();
|
||||
}
|
||||
});
|
||||
|
||||
/*provider.on('console', function(line) {
|
||||
//console.log(line);
|
||||
});*/
|
||||
|
||||
/*gprom.finally(function(ph) {
|
||||
ph.exit();
|
||||
// exit with a status code that actually gives information
|
||||
if (program.exitWithFailureCount) process.exit(failure_count);
|
||||
});*/
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
var Browser = require('zombie');
|
||||
var path = require('path');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Q = require('q');
|
||||
|
||||
var provide_emitter = function(file_paths) {
|
||||
var emitter = new EventEmitter();
|
||||
|
||||
file_paths.reduce(function(prom, file_path, path_ind) {
|
||||
return prom.then(function(browser) {
|
||||
browser.visit('file://'+file_path, function() {
|
||||
if (browser.error) throw new Error(browser.errors);
|
||||
|
||||
var res_json = {};
|
||||
res_json.file_ind = path_ind;
|
||||
|
||||
res_json.num_tests = browser.querySelectorAll('li.test').length;
|
||||
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.duration = browser.text('li.duration em');
|
||||
|
||||
var traverse_node = function(elem) {
|
||||
var classList = elem.className.split(' ');
|
||||
if (classList.indexOf('suite') > -1) {
|
||||
var 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);
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
var h2_content = elem.querySelector('h2').childNodes;
|
||||
var res = {
|
||||
type: 'test',
|
||||
text: h2_content[0].textContent
|
||||
}
|
||||
|
||||
if (classList.indexOf('pass') > -1) {
|
||||
res.pass = true;
|
||||
res.slow = classList.indexOf('fast') < 0;
|
||||
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);
|
||||
res_json.replay = browser.querySelector('a.replay').textContent;
|
||||
|
||||
emitter.emit('test_ready', res_json);
|
||||
});
|
||||
|
||||
return new Browser();
|
||||
});
|
||||
}, Q(new Browser()));
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
provide_emitter: provide_emitter,
|
||||
name: 'ZombieJS'
|
||||
}
|
Loading…
Reference in New Issue