source: Dev/trunk/node_modules/mocha/bin/_mocha

Last change on this file was 484, checked in by hendrikvanantwerpen, 11 years ago

Commit node_modules, to make checkouts and builds more deterministic.

  • Property svn:executable set to *
File size: 9.5 KB
RevLine 
[484]1#!/usr/bin/env node
2
3/**
4 * Module dependencies.
5 */
6
7var program = require('commander')
8  , sprintf = require('util').format
9  , path = require('path')
10  , fs = require('fs')
11  , glob = require('glob')
12  , resolve = path.resolve
13  , exists = fs.existsSync || path.existsSync
14  , Mocha = require('../')
15  , utils = Mocha.utils
16  , interfaces = Mocha.interfaces
17  , join = path.join
18  , basename = path.basename
19  , cwd = process.cwd()
20  , mocha = new Mocha;
21
22/**
23 * Save timer references to avoid Sinon interfering (see GH-237).
24 */
25
26var Date = global.Date
27  , setTimeout = global.setTimeout
28  , setInterval = global.setInterval
29  , clearTimeout = global.clearTimeout
30  , clearInterval = global.clearInterval;
31
32/**
33 * Files.
34 */
35
36var files = [];
37
38/**
39 * Globals.
40 */
41
42var globals = [];
43
44/**
45 * Requires.
46 */
47
48var requires = [];
49
50/**
51 * Images.
52 */
53
54var images = {
55    fail: __dirname + '/../images/error.png'
56  , pass: __dirname + '/../images/ok.png'
57};
58
59// options
60
61program
62  .version(JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8')).version)
63  .usage('[debug] [options] [files]')
64  .option('-r, --require <name>', 'require the given module')
65  .option('-R, --reporter <name>', 'specify the reporter to use', 'dot')
66  .option('-u, --ui <name>', 'specify user-interface (bdd|tdd|exports)', 'bdd')
67  .option('-g, --grep <pattern>', 'only run tests matching <pattern>')
68  .option('-i, --invert', 'inverts --grep matches')
69  .option('-t, --timeout <ms>', 'set test-case timeout in milliseconds [2000]')
70  .option('-s, --slow <ms>', '"slow" test threshold in milliseconds [75]')
71  .option('-w, --watch', 'watch files for changes')
72  .option('-c, --colors', 'force enabling of colors')
73  .option('-C, --no-colors', 'force disabling of colors')
74  .option('-G, --growl', 'enable growl notification support')
75  .option('-d, --debug', "enable node's debugger, synonym for node --debug")
76  .option('-b, --bail', "bail after first test failure")
77  .option('-A, --async-only', "force all tests to take a callback (async)")
78  .option('-S, --sort', "sort test files")
79  .option('--recursive', 'include sub directories')
80  .option('--debug-brk', "enable node's debugger breaking on the first line")
81  .option('--globals <names>', 'allow the given comma-delimited global [names]', list, [])
82  .option('--check-leaks', 'check for global variable leaks')
83  .option('--interfaces', 'display available interfaces')
84  .option('--reporters', 'display available reporters')
85  .option('--compilers <ext>:<module>,...', 'use the given module(s) to compile files', list, [])
86  .option('--inline-diffs', 'display actual/expected differences inline within each string')
87
88program.name = 'mocha';
89
90// init command
91
92program
93  .command('init <path>')
94  .description('initialize a client-side mocha setup at <path>')
95  .action(function(path){
96    var mkdir = require('mkdirp');
97    mkdir.sync(path);
98    var css = fs.readFileSync(join(__dirname, '..', 'mocha.css'));
99    var js = fs.readFileSync(join(__dirname, '..', 'mocha.js'));
100    var tmpl = fs.readFileSync(join(__dirname, '..', 'lib/template.html'));
101    fs.writeFileSync(join(path, 'mocha.css'), css);
102    fs.writeFileSync(join(path, 'mocha.js'), js);
103    fs.writeFileSync(join(path, 'tests.js'), '');
104    fs.writeFileSync(join(path, 'index.html'), tmpl);
105    process.exit(0);
106  });
107
108// --globals
109
110program.on('globals', function(val){
111  globals = globals.concat(list(val));
112});
113
114// --reporters
115
116program.on('reporters', function(){
117  console.log();
118  console.log('    dot - dot matrix');
119  console.log('    doc - html documentation');
120  console.log('    spec - hierarchical spec list');
121  console.log('    json - single json object');
122  console.log('    progress - progress bar');
123  console.log('    list - spec-style listing');
124  console.log('    tap - test-anything-protocol');
125  console.log('    landing - unicode landing strip');
126  console.log('    xunit - xunit reporter');
127  console.log('    html-cov - HTML test coverage');
128  console.log('    json-cov - JSON test coverage');
129  console.log('    min - minimal reporter (great with --watch)');
130  console.log('    json-stream - newline delimited json events');
131  console.log('    markdown - markdown documentation (github flavour)');
132  console.log('    nyan - nyan cat!');
133  console.log();
134  process.exit();
135});
136
137// --interfaces
138
139program.on('interfaces', function(){
140  console.log('');
141  console.log('    bdd');
142  console.log('    tdd');
143  console.log('    qunit');
144  console.log('    exports');
145  console.log('');
146  process.exit();
147});
148
149// -r, --require
150
151module.paths.push(cwd, join(cwd, 'node_modules'));
152
153program.on('require', function(mod){
154  var abs = exists(mod) || exists(mod + '.js');
155  if (abs) mod = resolve(mod);
156  requires.push(mod);
157});
158
159// mocha.opts support
160
161try {
162  var opts = fs.readFileSync('test/mocha.opts', 'utf8')
163    .trim()
164    .split(/\s+/);
165
166  process.argv = process.argv
167    .slice(0, 2)
168    .concat(opts.concat(process.argv.slice(2)));
169} catch (err) {
170  // ignore
171}
172
173// parse args
174
175program.parse(process.argv);
176
177// infinite stack traces
178
179Error.stackTraceLimit = Infinity; // TODO: config
180
181// reporter
182
183mocha.reporter(program.reporter);
184
185// interface
186
187mocha.ui(program.ui);
188
189// load reporter
190
191try {
192  Reporter = require('../lib/reporters/' + program.reporter);
193} catch (err) {
194  try {
195    Reporter = require(program.reporter);
196  } catch (err) {
197    throw new Error('reporter "' + program.reporter + '" does not exist');
198  }
199}
200
201// --no-colors
202
203if (!program.colors) mocha.useColors(false);
204
205// --colors
206
207if (~process.argv.indexOf('--colors') ||
208    ~process.argv.indexOf('-c')) {
209  mocha.useColors(true);
210}
211
212// --inline-diffs
213
214if (program.inlineDiffs) Base.inlineDiffs = true;
215
216// --slow <ms>
217
218if (program.slow) mocha.suite.slow(program.slow);
219
220// --timeout
221
222if (program.timeout) mocha.suite.timeout(program.timeout);
223
224// --bail
225
226mocha.suite.bail(program.bail);
227
228// --grep
229
230if (program.grep) mocha.grep(new RegExp(program.grep));
231
232// --invert
233
234if (program.invert) mocha.invert();
235
236// --check-leaks
237
238if (program.checkLeaks) mocha.checkLeaks();
239
240// --growl
241
242if (program.growl) mocha.growl();
243
244// --async-only
245
246if (program.asyncOnly) mocha.asyncOnly();
247
248// --globals
249
250mocha.globals(globals);
251
252// custom compiler support
253
254var extensions = ['js'];
255program.compilers.forEach(function(c) {
256  var compiler = c.split(':')
257    , ext = compiler[0]
258    , mod = compiler[1];
259
260  if (mod[0] == '.') mod = join(process.cwd(), mod);
261  require(mod);
262  extensions.push(ext);
263});
264
265var re = new RegExp('\\.(' + extensions.join('|') + ')$');
266
267// requires
268
269requires.forEach(function(mod) {
270  require(mod);
271});
272
273// files
274
275var files = []
276  , args = program.args;
277
278// default files to test/*.{js,coffee}
279
280if (!args.length) args.push('test');
281
282args.forEach(function(arg){
283  files = files.concat(lookupFiles(arg, program.recursive));
284});
285
286// resolve
287
288files = files.map(function(path){
289  return resolve(path);
290});
291
292if (program.sort) {
293  files.sort();
294}
295
296// --watch
297
298if (program.watch) {
299  console.log();
300  hideCursor();
301  process.on('SIGINT', function(){
302    showCursor();
303    console.log('\n');
304    process.exit();
305  });
306
307  var spinner = 'win32' == process.platform
308    ? ['|','/','-','\\']
309    : ['◜','◠','◝','◞','◡','◟'];
310
311  var frames = spinner.map(function(c) {
312    return sprintf('  \u001b[96m%s \u001b[90mwatching\u001b[0m', c);
313  });
314
315  var watchFiles = utils.files(cwd);
316
317  function loadAndRun() {
318    try {
319      mocha.files = files;
320      mocha.run(function(){
321        play(frames);
322      });
323    } catch(e) {
324      console.log(e.stack);
325    }
326  }
327
328  function purge() {
329    watchFiles.forEach(function(file){
330      delete require.cache[file];
331    });
332  }
333
334  loadAndRun();
335
336  utils.watch(watchFiles, function(){
337    purge();
338    stop()
339    mocha.suite = mocha.suite.clone();
340    mocha.ui(program.ui);
341    loadAndRun();
342  });
343
344  return;
345}
346
347// load
348
349mocha.files = files;
350mocha.run(process.exit);
351
352// enable growl notifications
353
354function growl(runner, reporter) {
355  var notify = require('growl');
356
357  runner.on('end', function(){
358    var stats = reporter.stats;
359    if (stats.failures) {
360      var msg = stats.failures + ' of ' + runner.total + ' tests failed';
361      notify(msg, { name: 'mocha', title: 'Failed', image: images.fail });
362    } else {
363      notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
364          name: 'mocha'
365        , title: 'Passed'
366        , image: images.pass
367      });
368    }
369  });
370}
371
372/**
373 * Parse list.
374 */
375
376function list(str) {
377  return str.split(/ *, */);
378}
379
380/**
381 * Hide the cursor.
382 */
383
384function hideCursor(){
385  process.stdout.write('\u001b[?25l');
386};
387
388/**
389 * Show the cursor.
390 */
391
392function showCursor(){
393  process.stdout.write('\u001b[?25h');
394};
395
396/**
397 * Stop play()ing.
398 */
399
400function stop() {
401  process.stdout.write('\u001b[2K');
402  clearInterval(play.timer);
403}
404
405/**
406 * Lookup file names at the given `path`.
407 */
408
409function lookupFiles(path, recursive) {
410  var files = [];
411
412  if (!exists(path)) {
413    if (exists(path + '.js')) {
414      path += '.js'
415    } else {
416      return glob.sync(path);
417    }
418  }
419
420  var stat = fs.statSync(path);
421  if (stat.isFile()) return path;
422
423  fs.readdirSync(path).forEach(function(file){
424    file = join(path, file);
425    var stat = fs.statSync(file);
426    if (stat.isDirectory()) {
427      if (recursive) files = files.concat(lookupFiles(file, recursive));
428      return
429    }
430    if (!stat.isFile() || !re.test(file) || basename(file)[0] == '.') return;
431    files.push(file);
432  });
433
434  return files;
435}
436
437/**
438 * Play the given array of strings.
439 */
440
441function play(arr, interval) {
442  var len = arr.length
443    , interval = interval || 100
444    , i = 0;
445
446  play.timer = setInterval(function(){
447    var str = arr[i++ % len];
448    process.stdout.write('\u001b[0G' + str);
449  }, interval);
450}
Note: See TracBrowser for help on using the repository browser.