UNPKG

6.49 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 track = require('../track'),
15 path = require('path'),
16 AssertionError = require('../assert').AssertionError;
17
18/**
19 * Reporter info string
20 */
21
22exports.info = "Nested test reporter";
23
24
25/**
26 * Run all tests within each module, reporting the results to the command-line.
27 *
28 * @param {Array} files
29 * @api public
30 */
31
32exports.run = function (files, options, callback) {
33
34 if (!options) {
35 // load default options
36 var content = fs.readFileSync(
37 __dirname + '/../../bin/nodeunit.json',
38 'utf8'
39 );
40 options = JSON.parse(content);
41 }
42
43 var error = function (str) {
44 return options.error_prefix + str + options.error_suffix;
45 };
46 var ok = function (str) {
47 return options.ok_prefix + str + options.ok_suffix;
48 };
49 var bold = function (str) {
50 return options.bold_prefix + str + options.bold_suffix;
51 };
52 var assertion_message = function (str) {
53 return options.assertion_prefix + str + options.assertion_suffix;
54 };
55 var fail_indicator = process.platform === 'win32' ? '\u00D7' : '✖';
56
57 var spaces_per_indent = options.spaces_per_indent || 4;
58
59 var start = new Date().getTime();
60 var paths = files.map(function (p) {
61 return path.resolve(p);
62 });
63 var tracker = track.createTracker(function (tracker) {
64 var i, names;
65 if (tracker.unfinished()) {
66 console.log('');
67 console.log(error(bold(
68 'FAILURES: Undone tests (or their setups/teardowns): '
69 )));
70 names = tracker.names();
71 for (i = 0; i < names.length; i += 1) {
72 console.log('- ' + names[i]);
73 }
74 console.log('');
75 console.log('To fix this, make sure all tests call test.done()');
76 process.reallyExit(tracker.unfinished());
77 }
78 });
79
80 // Object to hold status of each 'part' of the testCase/name array,
81 // i.e., whether this part has been printed yet.
82 tracker.already_printed = {};
83
84 var pass_text = function (txt) {
85 // Print in bold green.
86 return bold(ok(txt + " (pass)"));
87 };
88
89 var fail_text = function (txt) {
90 return bold(error(txt + " (fail) " + fail_indicator + " "));
91 };
92
93 var status_text = function (txt, status) {
94 if (status === 'pass') {
95 return pass_text(txt);
96 } else {
97 return fail_text(txt);
98 }
99 };
100
101 /**
102 * Slices an array, returns a string by joining the sliced elements.
103 * @example
104 * > name_slice(['TC1', 'TC1.1', 'mytest'], 1);
105 * "TC1,TC1.1"
106 */
107 var name_slice = function (name_arr, end_index) {
108 return name_arr.slice(0, end_index + 1).join(",");
109 };
110
111 var indent = (function () {
112 var txt = '';
113 var i;
114 for (i = 0; i < spaces_per_indent; i++) {
115 txt += ' ';
116 }
117 return txt;
118 }());
119
120 // Indent once for each indent_level
121 var add_indent = function (txt, indent_level) {
122 var k;
123 for (k = 0; k < indent_level; k++) {
124 txt += indent;
125 }
126 return txt;
127 };
128
129 // If it's not the last element of the name_arr, it's a testCase.
130 var is_testCase = function (name_arr, index) {
131 return index === name_arr.length - 1 ? false : true;
132 };
133
134 var testCase_line = function (txt) {
135 return txt + "\n";
136 };
137
138 /**
139 * Prints (console.log) the nested test status line(s).
140 *
141 * @param {Array} name_arr - Array of name elements.
142 * @param {String} status - either 'pass' or 'fail'.
143 * @example
144 * > print_status(['TC1', 'TC1.1', 'mytest'], 'pass');
145 * TC1
146 * TC1.1
147 * mytest (pass)
148 */
149 var print_status = function (name_arr, status) {
150 var txt = '';
151 var _name_slice, part, i;
152 for (i = 0; i < name_arr.length; i++) {
153 _name_slice = name_slice(name_arr, i);
154 part = name_arr[i];
155 if (!tracker.already_printed[_name_slice]) {
156 txt = add_indent(txt, i);
157 if (is_testCase(name_arr, i)) {
158 txt += testCase_line(part);
159 } else {
160 txt += status_text(part, status);
161 }
162 tracker.already_printed[_name_slice] = true;
163 }
164 }
165 console.log(txt);
166 };
167
168 nodeunit.runFiles(paths, {
169 testspec: options.testspec,
170 testFullSpec: options.testFullSpec,
171 moduleStart: function (name) {
172 console.log('\n' + bold(name));
173 },
174 testDone: function (name, assertions) {
175 tracker.remove(name);
176
177 if (!assertions.failures()) {
178 print_status(name, 'pass');
179 } else {
180 print_status(name, 'fail');
181 assertions.forEach(function (a) {
182 if (a.failed()) {
183 a = utils.betterErrors(a);
184 if (a.error instanceof AssertionError && a.message) {
185 console.log(
186 'Assertion Message: ' +
187 assertion_message(a.message)
188 );
189 }
190 console.log(a.error.stack + '\n');
191 }
192 });
193 }
194 },
195 done: function (assertions, end) {
196 end = end || new Date().getTime();
197 var duration = end - start;
198 if (assertions.failures()) {
199 console.log(
200 '\n' + bold(error('FAILURES: ')) + assertions.failures() +
201 '/' + assertions.length + ' assertions failed (' +
202 assertions.duration + 'ms)'
203 );
204 } else {
205 console.log(
206 '\n' + bold(ok('OK: ')) + assertions.length +
207 ' assertions (' + assertions.duration + 'ms)'
208 );
209 }
210
211 if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
212 },
213 testStart: function (name) {
214 tracker.put(name);
215 }
216 });
217};