UNPKG

5.7 kBJavaScriptView Raw
1/*!
2 * Nodeunit
3 * Copyright (c) 2010 Caolan McMahon
4 * MIT Licensed
5 */
6
7/**
8 * Module dependencies
9 */
10
11var nodeunit = require('../nodeunit'),
12 utils = require('../utils'),
13 fs = require('fs'),
14 path = require('path'),
15 async = require('../../deps/async'),
16 AssertionError = require('../assert').AssertionError,
17 child_process = require('child_process'),
18 ejs = require('ejs');
19
20
21/**
22 * Reporter info string
23 */
24
25exports.info = "jUnit XML test reports";
26
27
28/**
29 * Ensures a directory exists using mkdir -p.
30 *
31 * @param {String} path
32 * @param {Function} callback
33 * @api private
34 */
35
36var ensureDir = function (path, callback) {
37 var mkdir = child_process.spawn('mkdir', ['-p', path]);
38 mkdir.on('error', function (err) {
39 callback(err);
40 callback = function(){};
41 });
42 mkdir.on('exit', function (code) {
43 if (code === 0) callback();
44 else callback(new Error('mkdir exited with code: ' + code));
45 });
46};
47
48
49/**
50 * Returns absolute version of a path. Relative paths are interpreted
51 * relative to process.cwd() or the cwd parameter. Paths that are already
52 * absolute are returned unaltered.
53 *
54 * @param {String} p
55 * @param {String} cwd
56 * @return {String}
57 * @api public
58 */
59
60var abspath = function (p, /*optional*/cwd) {
61 if (p[0] === '/') return p;
62 cwd = cwd || process.cwd();
63 return path.normalize(path.resolve(p));
64};
65
66
67/**
68 * Run all tests within each module, reporting the results to the command-line,
69 * then writes out junit-compatible xml documents.
70 *
71 * @param {Array} files
72 * @api public
73 */
74
75exports.run = function (files, opts, callback) {
76 if (!opts.output) {
77 console.error(
78 'Error: No output directory defined.\n' +
79 '\tEither add an "output" property to your nodeunit.json config ' +
80 'file, or\n\tuse the --output command line option.'
81 );
82 return;
83 }
84 opts.output = abspath(opts.output);
85 var error = function (str) {
86 return opts.error_prefix + str + opts.error_suffix;
87 };
88 var ok = function (str) {
89 return opts.ok_prefix + str + opts.ok_suffix;
90 };
91 var bold = function (str) {
92 return opts.bold_prefix + str + opts.bold_suffix;
93 };
94
95 var start = new Date().getTime();
96 var paths = files.map(function (p) {
97 return path.resolve(p);
98 });
99
100 var modules = {};
101 var curModule;
102
103 nodeunit.runFiles(paths, {
104 testspec: opts.testspec,
105 testFullSpec: opts.testFullSpec,
106 moduleStart: function (name) {
107 curModule = {
108 errorCount: 0,
109 failureCount: 0,
110 tests: 0,
111 testcases: {},
112 name: name,
113 start: new Date().getTime()
114 };
115 modules[name] = curModule;
116 },
117 testStart: function(name) {
118 curModule.testcases[name] = {name: name, start : new Date().getTime()};
119 },
120 moduleDone: function(name) {
121 curModule.end = new Date().getTime();
122 },
123 testDone: function (name, assertions) {
124 var testcase = curModule.testcases[name];
125 testcase.end = new Date().getTime();
126 for (var i=0; i<assertions.length; i++) {
127 var a = assertions[i];
128 if (a.failed()) {
129 a = utils.betterErrors(a);
130 testcase.failure = {
131 message: a.message,
132 backtrace: a.error.stack
133 };
134
135 if (a.error instanceof AssertionError) {
136 curModule.failureCount++;
137 }
138 else {
139 curModule.errorCount++;
140 }
141 break;
142 }
143 }
144 curModule.tests++;
145 curModule.testcases[name] = testcase;;
146 },
147 done: function (assertions) {
148 var end = new Date().getTime();
149 var duration = end - start;
150
151 ensureDir(opts.output, function (err) {
152 var tmpl = __dirname + "/../../share/junit.xml.ejs";
153 fs.readFile(tmpl, function (err, data) {
154 if (err) throw err;
155 var tmpl = data.toString();
156 for(var k in modules) {
157 var module = modules[k];
158 var rendered = ejs.render(tmpl, {
159 suites: [module]
160 });
161 var filename = path.resolve(
162 opts.output,
163 module.name + '.xml'
164 );
165 console.log('Writing ' + filename);
166 fs.writeFileSync(filename, rendered, 'utf8');
167 }
168 if (assertions.failures()) {
169 console.log(
170 '\n' + bold(error('FAILURES: ')) +
171 assertions.failures() + '/' +
172 assertions.length + ' assertions failed (' +
173 assertions.duration + 'ms)'
174 );
175 }
176 else {
177 console.log(
178 '\n' + bold(ok('OK: ')) + assertions.length +
179 ' assertions (' + assertions.duration + 'ms)'
180 );
181 }
182
183 if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
184 });
185 });
186 }
187 });
188}