123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- #!/usr/bin/env node
- var ansi = require('ansi');
- var program = require('commander');
- var path = require('path');
- var fs = require('fs');
- 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')
- .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 .js tests).')
- .option('-o, --open-in-browser', 'Open the generated HTML files in a web browser using the "open" module (must be used with the "-g"/"--generate-html" option).')
- .option('--output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with .js tests)')
- .option('-d, --debug', 'Show debug output (the "console" event) from the provider')
- .option('-r, --relative', 'Use relative paths in the generated HTML file')
- .option('--debugger <port>', 'Enable the remote debugger for CasperJS')
- .parse(process.argv);
- if (program.tests.length === 0) {
- program.tests = fs.readdirSync(__dirname).filter(function(f) { return (/^test\.(\w|\.|-)+\.js$/).test(f); });
- program.tests = program.tests.map(function (f) { return path.resolve(__dirname, f); }); // add full paths in
- console.log('using files %s', program.tests);
- }
- var file_paths = [];
- var all_js = program.tests.reduce(function(a,e) { return a && e.slice(-3) == '.js'; }, true);
- var get_path = function (/* arguments */) {
- if (program.relative) {
- return path.join.apply(null, arguments);
- } else {
- var args = Array.prototype.slice.call(arguments);
- args.unshift(__dirname, '..');
- return path.resolve.apply(null, args);
- }
- };
- var get_path_cwd = function (/* arguments */) {
- if (program.relative) {
- var part_path = path.join.apply(null, arguments);
- return path.relative(path.join(__dirname, '..'), path.resolve(process.cwd(), part_path));
- } else {
- var args = Array.prototype.slice.call(arguments);
- args.unshift(process.cwd());
- return path.resolve.apply(null, args);
- }
- };
- if (all_js && !program.autoInject) {
- var all_modules = {};
- // uses the first instance of the string 'requires local modules: '
- program.tests.forEach(function (testname) {
- var full_path = path.resolve(process.cwd(), testname);
- var content = fs.readFileSync(full_path).toString();
- var ind = content.indexOf('requires local modules: ');
- if (ind > -1) {
- ind += 'requires local modules: '.length;
- var eol = content.indexOf('\n', ind);
- var modules = content.slice(ind, eol).split(/,\s*/);
- modules.forEach(function (mod) {
- all_modules[get_path('include/', mod) + '.js'] = 1;
- });
- }
- var fakes_ind = content.indexOf('requires test modules: ');
- if (fakes_ind > -1) {
- fakes_ind += 'requires test modules: '.length;
- var fakes_eol = content.indexOf('\n', fakes_ind);
- var fakes_modules = content.slice(fakes_ind, fakes_eol).split(/,\s*/);
- fakes_modules.forEach(function (mod) {
- all_modules[get_path('tests/', mod) + '.js'] = 1;
- });
- }
- });
- program.autoInject = Object.keys(all_modules);
- }
- if (program.autoInject) {
- var temp = require('temp');
- temp.track();
- var template = {
- header: "<html>\n<head>\n<meta charset='utf-8' />\n<link rel='stylesheet' href='" + get_path('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(function () { window.__mocha_done = true; });\n</script>\n</body>\n</html>"
- };
- template.header += "\n" + template.script_tag(get_path('node_modules/chai/chai.js'));
- template.header += "\n" + template.script_tag(get_path('node_modules/mocha/mocha.js'));
- template.header += "\n" + template.script_tag(get_path('node_modules/sinon/pkg/sinon.js'));
- template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
- template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
- template.header += "\n<script>mocha.setup('bdd');</script>";
- template.header = program.autoInject.reduce(function(acc, sn) {
- return acc + "\n" + template.script_tag(get_path_cwd(sn));
- }, template.header);
- file_paths = program.tests.map(function(jsn, ind) {
- var templ = template.header;
- templ += "\n";
- templ += template.script_tag(get_path_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 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 });
- if (program.outputHtml) {
- file_paths.forEach(function(path, path_ind) {
- fs.readFile(path, function(err, data) {
- if (err) {
- console.warn(error.stack);
- return;
- }
- if (use_ansi) {
- cursor
- .bold()
- .write(program.tests[path_ind])
- .reset()
- .write("\n")
- .write(Array(program.tests[path_ind].length+1).join('='))
- .write("\n\n");
- }
- cursor
- .write(data)
- .write("\n\n");
- });
- });
- }
- if (program.generateHtml) {
- var open_browser;
- if (program.openInBrowser) {
- open_browser = require('open');
- }
- file_paths.forEach(function(path, path_ind) {
- cursor
- .bold()
- .write(program.tests[path_ind])
- .write(": ")
- .reset()
- .write(path)
- .write("\n");
- if (program.openInBrowser) {
- open_browser(path);
- }
- });
- console.log('');
- }
- if (program.generateHtml) {
- process.stdin.resume(); // pause until C-c
- process.on('SIGINT', function() {
- process.stdin.pause(); // exit
- });
- }
- if (!program.outputHtml && !program.generateHtml) {
- var failure_count = 0;
- 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, program.debugger);
- 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, ')
- .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');
- if (test_json.num_skipped > 0) {
- cursor
- .reset()
- .write(', ')
- .grey()
- .write(''+test_json.num_skipped+' skipped');
- }
- cursor
- .reset()
- .write(' -- duration: '+test_json.duration+"s\n");
- console.log('');
- if (test_json.num_fails > 0 || program.printAll) {
- var extract_error_lines = function (err) {
- // the split is to avoid a weird thing where in PhantomJS where we get a stack trace too
- var err_lines = err.split('\n');
- if (err_lines.length == 1) {
- return err_lines[0];
- } else {
- var ind;
- for (ind = 0; ind < err_lines.length; ind++) {
- var at_ind = err_lines[ind].trim().indexOf('at ');
- if (at_ind === 0) {
- break;
- }
- }
- return err_lines.slice(0, ind).join('\n');
- }
- };
- 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(' '+extract_error_lines(node.error));
- 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
- //.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();
- }
- });
- if (program.debug) {
- provider.on('console', function(line) {
- // log to stderr
- console.error(line);
- });
- }
- provider.on('error', function(line) {
- // log to stderr
- console.error('ERROR: ' + line);
- });
- /*gprom.finally(function(ph) {
- ph.exit();
- // exit with a status code that actually gives information
- if (program.exitWithFailureCount) process.exit(failure_count);
- });*/
- }
|