UNPKG

10.7 kBJavaScriptView Raw
1(function(global) {
2 var UNDEFINED,
3 exportObject;
4
5 if (typeof module !== "undefined" && module.exports) {
6 exportObject = exports;
7 } else {
8 exportObject = global.jasmineReporters = global.jasmineReporters || {};
9 }
10
11 function elapsed(start, end) { return (end - start)/1000; }
12 function isFailed(obj) { return obj.status === "failed"; }
13 function isSkipped(obj) { return obj.status === "pending"; }
14 function isDisabled(obj) { return obj.status === "disabled"; }
15 function extend(dupe, obj) { // performs a shallow copy of all props of `obj` onto `dupe`
16 for (var prop in obj) {
17 if (obj.hasOwnProperty(prop)) {
18 dupe[prop] = obj[prop];
19 }
20 }
21 return dupe;
22 }
23 function log(str) {
24 var con = global.console || console;
25 if (con && con.log && str && str.length) {
26 con.log(str);
27 }
28 }
29
30
31 /**
32 * Basic reporter that outputs spec results to the terminal.
33 * Use this reporter in your build pipeline.
34 *
35 * Usage:
36 *
37 * jasmine.getEnv().addReporter(new jasmineReporters.TerminalReporter(options));
38 *
39 * @param {object} [options]
40 * @param {number} [options.verbosity] meaningful values are 0 through 3; anything
41 * greater than 3 is treated as 3 (default: 2)
42 * @param {boolean} [options.color] print in color or not (default: false)
43 * @param {boolean} [options.showStack] show stack trace for failed specs (default: false)
44 */
45 var DEFAULT_VERBOSITY = 2,
46 ATTRIBUTES_TO_ANSI = {
47 "off": 0,
48 "bold": 1,
49 "red": 31,
50 "green": 32,
51 "yellow": 33,
52 "blue": 34,
53 "magenta": 35,
54 "cyan": 36
55 };
56
57 exportObject.TerminalReporter = function(options) {
58 var self = this;
59 self.started = false;
60 self.finished = false;
61
62 // sanitize arguments
63 options = options || {};
64 self.verbosity = typeof options.verbosity === "number" ? options.verbosity : DEFAULT_VERBOSITY;
65 self.color = options.color;
66 self.showStack = options.showStack;
67
68 var indent_string = " ",
69 startTime,
70 currentSuite = null,
71 totalSpecsExecuted = 0,
72 totalSpecsSkipped = 0,
73 totalSpecsDisabled = 0,
74 totalSpecsFailed = 0,
75 totalSpecsDefined,
76 // when use use fit, jasmine never calls suiteStarted / suiteDone, so make a fake one to use
77 fakeFocusedSuite = {
78 id: "focused",
79 description: "focused specs",
80 fullName: "focused specs"
81 };
82
83 var __suites = {}, __specs = {};
84 function getSuite(suite) {
85 __suites[suite.id] = extend(__suites[suite.id] || {}, suite);
86 return __suites[suite.id];
87 }
88 function getSpec(spec, suite) {
89 __specs[spec.id] = extend(__specs[spec.id] || {}, spec);
90 var ret = __specs[spec.id];
91 if (suite && !ret._suite) {
92 ret._suite = suite;
93 ret._depth = suite._depth+1;
94 suite._specs++;
95 }
96 return ret;
97 }
98
99 self.jasmineStarted = function(summary) {
100 totalSpecsDefined = summary && summary.totalSpecsDefined || NaN;
101 startTime = exportObject.startTime = new Date();
102 self.started = true;
103 };
104 self.suiteStarted = function(suite) {
105 suite = getSuite(suite);
106 suite._specs = 0;
107 suite._nestedSpecs = 0;
108 suite._failures = 0;
109 suite._nestedFailures = 0;
110 suite._skipped = 0;
111 suite._nestedSkipped = 0;
112 suite._disabled = 0;
113 suite._nestedDisabled = 0;
114 suite._depth = currentSuite ? currentSuite._depth+1 : 1;
115 suite._parent = currentSuite;
116 currentSuite = suite;
117 if (self.verbosity > 2) {
118 log(indentWithLevel(suite._depth, inColor(suite.description, "bold")));
119 }
120 };
121 self.specStarted = function(spec) {
122 if (!currentSuite) {
123 // focused spec (fit) -- suiteStarted was never called
124 self.suiteStarted(fakeFocusedSuite);
125 }
126 spec = getSpec(spec, currentSuite);
127 if (self.verbosity > 2) {
128 log(indentWithLevel(spec._depth, spec.description + " ..."));
129 }
130 };
131 self.specDone = function(spec) {
132 spec = getSpec(spec, currentSuite);
133 var failed = false,
134 skipped = false,
135 disabled = false,
136 color = "green",
137 resultText = "";
138 if (isSkipped(spec)) {
139 skipped = true;
140 color = "cyan";
141 spec._suite._skipped++;
142 totalSpecsSkipped++;
143 }
144 if (isFailed(spec)) {
145 failed = true;
146 color = "red";
147 spec._suite._failures++;
148 totalSpecsFailed++;
149 }
150 if (isDisabled(spec)) {
151 disabled = true;
152 color = "yellow";
153 spec._suite._disabled++;
154 totalSpecsDisabled++;
155 }
156 totalSpecsExecuted++;
157
158 if (self.verbosity === 2) {
159 resultText = failed ? "F" : skipped ? "S" : disabled ? "D" : ".";
160 } else if (self.verbosity > 2) {
161 resultText = " " + (failed ? "Failed" : skipped ? "Skipped" : disabled ? "Disabled" : "Passed");
162 }
163 log(inColor(resultText, color));
164
165 if (skipped && spec.pendingReason) {
166 if (self.verbosity > 2) {
167 log(indentWithLevel(spec._depth, inColor(spec.pendingReason, color)));
168 }
169 else {
170 log(inColor(spec.pendingReason, color));
171 }
172 }
173
174 if (failed) {
175 if (self.verbosity === 1) {
176 log(spec.fullName);
177 } else if (self.verbosity === 2) {
178 log(" ");
179 log(indentWithLevel(spec._depth, spec.fullName));
180 }
181
182 for (var i = 0; i < spec.failedExpectations.length; i++) {
183 log(inColor(indentWithLevel(spec._depth, indent_string + spec.failedExpectations[i].message), color));
184 if (self.showStack){
185 logStackLines(spec._depth, spec.failedExpectations[i].stack.split("\n"));
186 }
187 }
188 }
189 };
190 self.suiteDone = function(suite) {
191 suite = getSuite(suite);
192 if (suite._parent === UNDEFINED) {
193 // disabled suite (xdescribe) -- suiteStarted was never called
194 self.suiteStarted(suite);
195 }
196 if (suite._parent) {
197 suite._parent._specs += suite._specs + suite._nestedSpecs;
198 suite._parent._failures += suite._failures + suite._nestedFailures;
199 suite._parent._skipped += suite._skipped + suite._nestedSkipped;
200 suite._parent._disabled += suite._disabled + suite._nestedDisabled;
201
202 }
203 currentSuite = suite._parent;
204 if (self.verbosity < 3) {
205 return;
206 }
207
208 var total = suite._specs + suite._nestedSpecs,
209 failed = suite._failures + suite._nestedFailures,
210 skipped = suite._skipped + suite._nestedSkipped,
211 disabled = suite._disabled + suite._nestedDisabled,
212 passed = total - failed - skipped,
213 color = failed ? "red+bold" : "green+bold",
214 str = passed + " of " + total + " passed (" + skipped + " skipped, " + disabled + " disabled)";
215 log(indentWithLevel(suite._depth, inColor(str+".", color)));
216 };
217 self.jasmineDone = function() {
218 if (currentSuite) {
219 // focused spec (fit) -- suiteDone was never called
220 self.suiteDone(fakeFocusedSuite);
221 }
222 var now = new Date(),
223 dur = elapsed(startTime, now),
224 total = totalSpecsDefined || totalSpecsExecuted,
225 disabled = total - totalSpecsExecuted + totalSpecsDisabled,
226 skipped = totalSpecsSkipped,
227 spec_str = total + (total === 1 ? " spec, " : " specs, "),
228 fail_str = totalSpecsFailed + (totalSpecsFailed === 1 ? " failure, " : " failures, "),
229 skip_str = skipped + " skipped, ",
230 disabled_str = disabled + " disabled in ",
231 summary_str = spec_str + fail_str + skip_str + disabled_str + dur + "s.",
232 result_str = (totalSpecsFailed && "FAILURE: " || "SUCCESS: ") + summary_str,
233 result_color = totalSpecsFailed && "red+bold" || "green+bold";
234
235 if (self.verbosity === 2) {
236 log("");
237 }
238
239 if (self.verbosity > 0) {
240 log(inColor(result_str, result_color));
241 }
242 //log("Specs skipped but not reported (entire suite skipped or targeted to specific specs)", totalSpecsDefined - totalSpecsExecuted + totalSpecsDisabled);
243
244 self.finished = true;
245 // this is so phantomjs-testrunner.js can tell if we're done executing
246 exportObject.endTime = now;
247 };
248 function indentWithLevel(level, string) {
249 if (!string || !string.length) {
250 return "";
251 }
252 return new Array(level).join(indent_string) + string;
253 }
254 function logStackLines(depth, lines) {
255 lines.forEach(function(line){
256 log(inColor(indentWithLevel(depth, indent_string + line), "magenta"));
257 });
258 }
259 function inColor(string, color) {
260 var color_attributes = color && color.split("+"),
261 ansi_string = "",
262 i;
263
264 if (!string || !string.length) {
265 return "";
266 } else if (!self.color || !color_attributes) {
267 return string;
268 }
269
270 for(i = 0; i < color_attributes.length; i++) {
271 ansi_string += "\u001b[" + ATTRIBUTES_TO_ANSI[color_attributes[i]] + "m";
272 }
273 ansi_string += string + "\u001b[" + ATTRIBUTES_TO_ANSI["off"] + "m";
274
275 return ansi_string;
276 }
277 };
278})(this);