Forráskód Böngészése

Merge pull request #322 from DirectXMan12/master

Support Running Mocha Tests from the Console
Solly 11 éve
szülő
commit
e0dc102e5b

+ 90 - 0
tests/run_from_console.casper.js

@@ -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)'
+}

+ 196 - 0
tests/run_from_console.js

@@ -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);
+});*/
+

+ 73 - 0
tests/run_from_console.zombie.js

@@ -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'
+}