extract latest git commit ID from github, MKWS-420
[mkws-moved-to-github.git] / examples / jasmine / lib / jasmine-1.3.1 / jasmine-html.js
1 jasmine.HtmlReporterHelpers = {};
2
3 jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
4   var el = document.createElement(type);
5
6   for (var i = 2; i < arguments.length; i++) {
7     var child = arguments[i];
8
9     if (typeof child === 'string') {
10       el.appendChild(document.createTextNode(child));
11     } else {
12       if (child) {
13         el.appendChild(child);
14       }
15     }
16   }
17
18   for (var attr in attrs) {
19     if (attr == "className") {
20       el[attr] = attrs[attr];
21     } else {
22       el.setAttribute(attr, attrs[attr]);
23     }
24   }
25
26   return el;
27 };
28
29 jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
30   var results = child.results();
31   var status = results.passed() ? 'passed' : 'failed';
32   if (results.skipped) {
33     status = 'skipped';
34   }
35
36   return status;
37 };
38
39 jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
40   var parentDiv = this.dom.summary;
41   var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
42   var parent = child[parentSuite];
43
44   if (parent) {
45     if (typeof this.views.suites[parent.id] == 'undefined') {
46       this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
47     }
48     parentDiv = this.views.suites[parent.id].element;
49   }
50
51   parentDiv.appendChild(childElement);
52 };
53
54
55 jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
56   for(var fn in jasmine.HtmlReporterHelpers) {
57     ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
58   }
59 };
60
61 jasmine.HtmlReporter = function(_doc) {
62   var self = this;
63   var doc = _doc || window.document;
64
65   var reporterView;
66
67   var dom = {};
68
69   // Jasmine Reporter Public Interface
70   self.logRunningSpecs = false;
71
72   self.reportRunnerStarting = function(runner) {
73     var specs = runner.specs() || [];
74
75     if (specs.length == 0) {
76       return;
77     }
78
79     createReporterDom(runner.env.versionString());
80     doc.body.appendChild(dom.reporter);
81     setExceptionHandling();
82
83     reporterView = new jasmine.HtmlReporter.ReporterView(dom);
84     reporterView.addSpecs(specs, self.specFilter);
85   };
86
87   self.reportRunnerResults = function(runner) {
88     reporterView && reporterView.complete();
89   };
90
91   self.reportSuiteResults = function(suite) {
92     reporterView.suiteComplete(suite);
93   };
94
95   self.reportSpecStarting = function(spec) {
96     if (self.logRunningSpecs) {
97       self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
98     }
99   };
100
101   self.reportSpecResults = function(spec) {
102     reporterView.specComplete(spec);
103   };
104
105   self.log = function() {
106     var console = jasmine.getGlobal().console;
107     if (console && console.log) {
108       if (console.log.apply) {
109         console.log.apply(console, arguments);
110       } else {
111         console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
112       }
113     }
114   };
115
116   self.specFilter = function(spec) {
117     if (!focusedSpecName()) {
118       return true;
119     }
120
121     return spec.getFullName().indexOf(focusedSpecName()) === 0;
122   };
123
124   return self;
125
126   function focusedSpecName() {
127     var specName;
128
129     (function memoizeFocusedSpec() {
130       if (specName) {
131         return;
132       }
133
134       var paramMap = [];
135       var params = jasmine.HtmlReporter.parameters(doc);
136
137       for (var i = 0; i < params.length; i++) {
138         var p = params[i].split('=');
139         paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
140       }
141
142       specName = paramMap.spec;
143     })();
144
145     return specName;
146   }
147
148   function createReporterDom(version) {
149     dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
150       dom.banner = self.createDom('div', { className: 'banner' },
151         self.createDom('span', { className: 'title' }, "Jasmine "),
152         self.createDom('span', { className: 'version' }, version)),
153
154       dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
155       dom.alert = self.createDom('div', {className: 'alert'},
156         self.createDom('span', { className: 'exceptions' },
157           self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
158           self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
159       dom.results = self.createDom('div', {className: 'results'},
160         dom.summary = self.createDom('div', { className: 'summary' }),
161         dom.details = self.createDom('div', { id: 'details' }))
162     );
163   }
164
165   function noTryCatch() {
166     return window.location.search.match(/catch=false/);
167   }
168
169   function searchWithCatch() {
170     var params = jasmine.HtmlReporter.parameters(window.document);
171     var removed = false;
172     var i = 0;
173
174     while (!removed && i < params.length) {
175       if (params[i].match(/catch=/)) {
176         params.splice(i, 1);
177         removed = true;
178       }
179       i++;
180     }
181     if (jasmine.CATCH_EXCEPTIONS) {
182       params.push("catch=false");
183     }
184
185     return params.join("&");
186   }
187
188   function setExceptionHandling() {
189     var chxCatch = document.getElementById('no_try_catch');
190
191     if (noTryCatch()) {
192       chxCatch.setAttribute('checked', true);
193       jasmine.CATCH_EXCEPTIONS = false;
194     }
195     chxCatch.onclick = function() {
196       window.location.search = searchWithCatch();
197     };
198   }
199 };
200 jasmine.HtmlReporter.parameters = function(doc) {
201   var paramStr = doc.location.search.substring(1);
202   var params = [];
203
204   if (paramStr.length > 0) {
205     params = paramStr.split('&');
206   }
207   return params;
208 }
209 jasmine.HtmlReporter.sectionLink = function(sectionName) {
210   var link = '?';
211   var params = [];
212
213   if (sectionName) {
214     params.push('spec=' + encodeURIComponent(sectionName));
215   }
216   if (!jasmine.CATCH_EXCEPTIONS) {
217     params.push("catch=false");
218   }
219   if (params.length > 0) {
220     link += params.join("&");
221   }
222
223   return link;
224 };
225 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
226 jasmine.HtmlReporter.ReporterView = function(dom) {
227   this.startedAt = new Date();
228   this.runningSpecCount = 0;
229   this.completeSpecCount = 0;
230   this.passedCount = 0;
231   this.failedCount = 0;
232   this.skippedCount = 0;
233
234   this.createResultsMenu = function() {
235     this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
236       this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
237       ' | ',
238       this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
239
240     this.summaryMenuItem.onclick = function() {
241       dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
242     };
243
244     this.detailsMenuItem.onclick = function() {
245       showDetails();
246     };
247   };
248
249   this.addSpecs = function(specs, specFilter) {
250     this.totalSpecCount = specs.length;
251
252     this.views = {
253       specs: {},
254       suites: {}
255     };
256
257     for (var i = 0; i < specs.length; i++) {
258       var spec = specs[i];
259       this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
260       if (specFilter(spec)) {
261         this.runningSpecCount++;
262       }
263     }
264   };
265
266   this.specComplete = function(spec) {
267     this.completeSpecCount++;
268
269     if (isUndefined(this.views.specs[spec.id])) {
270       this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
271     }
272
273     var specView = this.views.specs[spec.id];
274
275     switch (specView.status()) {
276       case 'passed':
277         this.passedCount++;
278         break;
279
280       case 'failed':
281         this.failedCount++;
282         break;
283
284       case 'skipped':
285         this.skippedCount++;
286         break;
287     }
288
289     specView.refresh();
290     this.refresh();
291   };
292
293   this.suiteComplete = function(suite) {
294     var suiteView = this.views.suites[suite.id];
295     if (isUndefined(suiteView)) {
296       return;
297     }
298     suiteView.refresh();
299   };
300
301   this.refresh = function() {
302
303     if (isUndefined(this.resultsMenu)) {
304       this.createResultsMenu();
305     }
306
307     // currently running UI
308     if (isUndefined(this.runningAlert)) {
309       this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
310       dom.alert.appendChild(this.runningAlert);
311     }
312     this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
313
314     // skipped specs UI
315     if (isUndefined(this.skippedAlert)) {
316       this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
317     }
318
319     this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
320
321     if (this.skippedCount === 1 && isDefined(dom.alert)) {
322       dom.alert.appendChild(this.skippedAlert);
323     }
324
325     // passing specs UI
326     if (isUndefined(this.passedAlert)) {
327       this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
328     }
329     this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
330
331     // failing specs UI
332     if (isUndefined(this.failedAlert)) {
333       this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
334     }
335     this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
336
337     if (this.failedCount === 1 && isDefined(dom.alert)) {
338       dom.alert.appendChild(this.failedAlert);
339       dom.alert.appendChild(this.resultsMenu);
340     }
341
342     // summary info
343     this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
344     this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
345   };
346
347   this.complete = function() {
348     dom.alert.removeChild(this.runningAlert);
349
350     this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
351
352     if (this.failedCount === 0) {
353       dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
354     } else {
355       showDetails();
356     }
357
358     dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
359   };
360
361   return this;
362
363   function showDetails() {
364     if (dom.reporter.className.search(/showDetails/) === -1) {
365       dom.reporter.className += " showDetails";
366     }
367   }
368
369   function isUndefined(obj) {
370     return typeof obj === 'undefined';
371   }
372
373   function isDefined(obj) {
374     return !isUndefined(obj);
375   }
376
377   function specPluralizedFor(count) {
378     var str = count + " spec";
379     if (count > 1) {
380       str += "s"
381     }
382     return str;
383   }
384
385 };
386
387 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
388
389
390 jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
391   this.spec = spec;
392   this.dom = dom;
393   this.views = views;
394
395   this.symbol = this.createDom('li', { className: 'pending' });
396   this.dom.symbolSummary.appendChild(this.symbol);
397
398   this.summary = this.createDom('div', { className: 'specSummary' },
399     this.createDom('a', {
400       className: 'description',
401       href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()),
402       title: this.spec.getFullName()
403     }, this.spec.description)
404   );
405
406   this.detail = this.createDom('div', { className: 'specDetail' },
407       this.createDom('a', {
408         className: 'description',
409         href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
410         title: this.spec.getFullName()
411       }, this.spec.getFullName())
412   );
413 };
414
415 jasmine.HtmlReporter.SpecView.prototype.status = function() {
416   return this.getSpecStatus(this.spec);
417 };
418
419 jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
420   this.symbol.className = this.status();
421
422   switch (this.status()) {
423     case 'skipped':
424       break;
425
426     case 'passed':
427       this.appendSummaryToSuiteDiv();
428       break;
429
430     case 'failed':
431       this.appendSummaryToSuiteDiv();
432       this.appendFailureDetail();
433       break;
434   }
435 };
436
437 jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
438   this.summary.className += ' ' + this.status();
439   this.appendToSummary(this.spec, this.summary);
440 };
441
442 jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
443   this.detail.className += ' ' + this.status();
444
445   var resultItems = this.spec.results().getItems();
446   var messagesDiv = this.createDom('div', { className: 'messages' });
447
448   for (var i = 0; i < resultItems.length; i++) {
449     var result = resultItems[i];
450
451     if (result.type == 'log') {
452       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
453     } else if (result.type == 'expect' && result.passed && !result.passed()) {
454       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
455
456       if (result.trace.stack) {
457         messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
458       }
459     }
460   }
461
462   if (messagesDiv.childNodes.length > 0) {
463     this.detail.appendChild(messagesDiv);
464     this.dom.details.appendChild(this.detail);
465   }
466 };
467
468 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
469   this.suite = suite;
470   this.dom = dom;
471   this.views = views;
472
473   this.element = this.createDom('div', { className: 'suite' },
474     this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
475   );
476
477   this.appendToSummary(this.suite, this.element);
478 };
479
480 jasmine.HtmlReporter.SuiteView.prototype.status = function() {
481   return this.getSpecStatus(this.suite);
482 };
483
484 jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
485   this.element.className += " " + this.status();
486 };
487
488 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
489
490 /* @deprecated Use jasmine.HtmlReporter instead
491  */
492 jasmine.TrivialReporter = function(doc) {
493   this.document = doc || document;
494   this.suiteDivs = {};
495   this.logRunningSpecs = false;
496 };
497
498 jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
499   var el = document.createElement(type);
500
501   for (var i = 2; i < arguments.length; i++) {
502     var child = arguments[i];
503
504     if (typeof child === 'string') {
505       el.appendChild(document.createTextNode(child));
506     } else {
507       if (child) { el.appendChild(child); }
508     }
509   }
510
511   for (var attr in attrs) {
512     if (attr == "className") {
513       el[attr] = attrs[attr];
514     } else {
515       el.setAttribute(attr, attrs[attr]);
516     }
517   }
518
519   return el;
520 };
521
522 jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
523   var showPassed, showSkipped;
524
525   this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
526       this.createDom('div', { className: 'banner' },
527         this.createDom('div', { className: 'logo' },
528             this.createDom('span', { className: 'title' }, "Jasmine"),
529             this.createDom('span', { className: 'version' }, runner.env.versionString())),
530         this.createDom('div', { className: 'options' },
531             "Show ",
532             showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
533             this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
534             showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
535             this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
536             )
537           ),
538
539       this.runnerDiv = this.createDom('div', { className: 'runner running' },
540           this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
541           this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
542           this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
543       );
544
545   this.document.body.appendChild(this.outerDiv);
546
547   var suites = runner.suites();
548   for (var i = 0; i < suites.length; i++) {
549     var suite = suites[i];
550     var suiteDiv = this.createDom('div', { className: 'suite' },
551         this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
552         this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
553     this.suiteDivs[suite.id] = suiteDiv;
554     var parentDiv = this.outerDiv;
555     if (suite.parentSuite) {
556       parentDiv = this.suiteDivs[suite.parentSuite.id];
557     }
558     parentDiv.appendChild(suiteDiv);
559   }
560
561   this.startedAt = new Date();
562
563   var self = this;
564   showPassed.onclick = function(evt) {
565     if (showPassed.checked) {
566       self.outerDiv.className += ' show-passed';
567     } else {
568       self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
569     }
570   };
571
572   showSkipped.onclick = function(evt) {
573     if (showSkipped.checked) {
574       self.outerDiv.className += ' show-skipped';
575     } else {
576       self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
577     }
578   };
579 };
580
581 jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
582   var results = runner.results();
583   var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
584   this.runnerDiv.setAttribute("class", className);
585   //do it twice for IE
586   this.runnerDiv.setAttribute("className", className);
587   var specs = runner.specs();
588   var specCount = 0;
589   for (var i = 0; i < specs.length; i++) {
590     if (this.specFilter(specs[i])) {
591       specCount++;
592     }
593   }
594   var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
595   message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
596   this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
597
598   this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
599 };
600
601 jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
602   var results = suite.results();
603   var status = results.passed() ? 'passed' : 'failed';
604   if (results.totalCount === 0) { // todo: change this to check results.skipped
605     status = 'skipped';
606   }
607   this.suiteDivs[suite.id].className += " " + status;
608 };
609
610 jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
611   if (this.logRunningSpecs) {
612     this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
613   }
614 };
615
616 jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
617   var results = spec.results();
618   var status = results.passed() ? 'passed' : 'failed';
619   if (results.skipped) {
620     status = 'skipped';
621   }
622   var specDiv = this.createDom('div', { className: 'spec '  + status },
623       this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
624       this.createDom('a', {
625         className: 'description',
626         href: '?spec=' + encodeURIComponent(spec.getFullName()),
627         title: spec.getFullName()
628       }, spec.description));
629
630
631   var resultItems = results.getItems();
632   var messagesDiv = this.createDom('div', { className: 'messages' });
633   for (var i = 0; i < resultItems.length; i++) {
634     var result = resultItems[i];
635
636     if (result.type == 'log') {
637       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
638     } else if (result.type == 'expect' && result.passed && !result.passed()) {
639       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
640
641       if (result.trace.stack) {
642         messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
643       }
644     }
645   }
646
647   if (messagesDiv.childNodes.length > 0) {
648     specDiv.appendChild(messagesDiv);
649   }
650
651   this.suiteDivs[spec.suite.id].appendChild(specDiv);
652 };
653
654 jasmine.TrivialReporter.prototype.log = function() {
655   var console = jasmine.getGlobal().console;
656   if (console && console.log) {
657     if (console.log.apply) {
658       console.log.apply(console, arguments);
659     } else {
660       console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
661     }
662   }
663 };
664
665 jasmine.TrivialReporter.prototype.getLocation = function() {
666   return this.document.location;
667 };
668
669 jasmine.TrivialReporter.prototype.specFilter = function(spec) {
670   var paramMap = {};
671   var params = this.getLocation().search.substring(1).split('&');
672   for (var i = 0; i < params.length; i++) {
673     var p = params[i].split('=');
674     paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
675   }
676
677   if (!paramMap.spec) {
678     return true;
679   }
680   return spec.getFullName().indexOf(paramMap.spec) === 0;
681 };