1 | |
---|
2 | /** |
---|
3 | * Module dependencies. |
---|
4 | */ |
---|
5 | |
---|
6 | var Base = require('./base') |
---|
7 | , utils = require('../utils') |
---|
8 | , escape = utils.escape; |
---|
9 | |
---|
10 | /** |
---|
11 | * Save timer references to avoid Sinon interfering (see GH-237). |
---|
12 | */ |
---|
13 | |
---|
14 | var Date = global.Date |
---|
15 | , setTimeout = global.setTimeout |
---|
16 | , setInterval = global.setInterval |
---|
17 | , clearTimeout = global.clearTimeout |
---|
18 | , clearInterval = global.clearInterval; |
---|
19 | |
---|
20 | /** |
---|
21 | * Expose `XUnit`. |
---|
22 | */ |
---|
23 | |
---|
24 | exports = module.exports = XUnit; |
---|
25 | |
---|
26 | /** |
---|
27 | * Initialize a new `XUnit` reporter. |
---|
28 | * |
---|
29 | * @param {Runner} runner |
---|
30 | * @api public |
---|
31 | */ |
---|
32 | |
---|
33 | function XUnit(runner) { |
---|
34 | Base.call(this, runner); |
---|
35 | var stats = this.stats |
---|
36 | , tests = [] |
---|
37 | , self = this; |
---|
38 | |
---|
39 | runner.on('pass', function(test){ |
---|
40 | tests.push(test); |
---|
41 | }); |
---|
42 | |
---|
43 | runner.on('fail', function(test){ |
---|
44 | tests.push(test); |
---|
45 | }); |
---|
46 | |
---|
47 | runner.on('end', function(){ |
---|
48 | console.log(tag('testsuite', { |
---|
49 | name: 'Mocha Tests' |
---|
50 | , tests: stats.tests |
---|
51 | , failures: stats.failures |
---|
52 | , errors: stats.failures |
---|
53 | , skipped: stats.tests - stats.failures - stats.passes |
---|
54 | , timestamp: (new Date).toUTCString() |
---|
55 | , time: (stats.duration / 1000) || 0 |
---|
56 | }, false)); |
---|
57 | |
---|
58 | tests.forEach(test); |
---|
59 | console.log('</testsuite>'); |
---|
60 | }); |
---|
61 | } |
---|
62 | |
---|
63 | /** |
---|
64 | * Inherit from `Base.prototype`. |
---|
65 | */ |
---|
66 | |
---|
67 | XUnit.prototype.__proto__ = Base.prototype; |
---|
68 | |
---|
69 | /** |
---|
70 | * Output tag for the given `test.` |
---|
71 | */ |
---|
72 | |
---|
73 | function test(test) { |
---|
74 | var attrs = { |
---|
75 | classname: test.parent.fullTitle() |
---|
76 | , name: test.title |
---|
77 | , time: test.duration / 1000 |
---|
78 | }; |
---|
79 | |
---|
80 | if ('failed' == test.state) { |
---|
81 | var err = test.err; |
---|
82 | attrs.message = escape(err.message); |
---|
83 | console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); |
---|
84 | } else if (test.pending) { |
---|
85 | console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); |
---|
86 | } else { |
---|
87 | console.log(tag('testcase', attrs, true) ); |
---|
88 | } |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | * HTML tag helper. |
---|
93 | */ |
---|
94 | |
---|
95 | function tag(name, attrs, close, content) { |
---|
96 | var end = close ? '/>' : '>' |
---|
97 | , pairs = [] |
---|
98 | , tag; |
---|
99 | |
---|
100 | for (var key in attrs) { |
---|
101 | pairs.push(key + '="' + escape(attrs[key]) + '"'); |
---|
102 | } |
---|
103 | |
---|
104 | tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; |
---|
105 | if (content) tag += content + '</' + name + end; |
---|
106 | return tag; |
---|
107 | } |
---|
108 | |
---|
109 | /** |
---|
110 | * Return cdata escaped CDATA `str`. |
---|
111 | */ |
---|
112 | |
---|
113 | function cdata(str) { |
---|
114 | return '<![CDATA[' + escape(str) + ']]>'; |
---|
115 | } |
---|