1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | var Base = require('./base');
|
8 | var utils = require('../utils');
|
9 | var inherits = utils.inherits;
|
10 | var fs = require('fs');
|
11 | var escape = utils.escape;
|
12 | var mkdirp = require('mkdirp');
|
13 | var path = require('path');
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | var Date = global.Date;
|
21 | var setTimeout = global.setTimeout;
|
22 | var setInterval = global.setInterval;
|
23 | var clearTimeout = global.clearTimeout;
|
24 | var clearInterval = global.clearInterval;
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | exports = module.exports = XUnit;
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | function XUnit (runner, options) {
|
40 | Base.call(this, runner);
|
41 |
|
42 | var stats = this.stats;
|
43 | var tests = [];
|
44 | var self = this;
|
45 |
|
46 | if (options && options.reporterOptions && options.reporterOptions.output) {
|
47 | if (!fs.createWriteStream) {
|
48 | throw new Error('file output not supported in browser');
|
49 | }
|
50 | mkdirp.sync(path.dirname(options.reporterOptions.output));
|
51 | self.fileStream = fs.createWriteStream(options.reporterOptions.output);
|
52 | }
|
53 |
|
54 | runner.on('pending', function (test) {
|
55 | tests.push(test);
|
56 | });
|
57 |
|
58 | runner.on('pass', function (test) {
|
59 | tests.push(test);
|
60 | });
|
61 |
|
62 | runner.on('fail', function (test) {
|
63 | tests.push(test);
|
64 | });
|
65 |
|
66 | runner.on('end', function () {
|
67 | self.write(tag('testsuite', {
|
68 | name: 'Mocha Tests',
|
69 | tests: stats.tests,
|
70 | failures: stats.failures,
|
71 | errors: stats.failures,
|
72 | skipped: stats.tests - stats.failures - stats.passes,
|
73 | timestamp: (new Date()).toUTCString(),
|
74 | time: (stats.duration / 1000) || 0
|
75 | }, false));
|
76 |
|
77 | tests.forEach(function (t) {
|
78 | self.test(t);
|
79 | });
|
80 |
|
81 | self.write('</testsuite>');
|
82 | });
|
83 | }
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | inherits(XUnit, Base);
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | XUnit.prototype.done = function (failures, fn) {
|
97 | if (this.fileStream) {
|
98 | this.fileStream.end(function () {
|
99 | fn(failures);
|
100 | });
|
101 | } else {
|
102 | fn(failures);
|
103 | }
|
104 | };
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | XUnit.prototype.write = function (line) {
|
112 | if (this.fileStream) {
|
113 | this.fileStream.write(line + '\n');
|
114 | } else if (typeof process === 'object' && process.stdout) {
|
115 | process.stdout.write(line + '\n');
|
116 | } else {
|
117 | console.log(line);
|
118 | }
|
119 | };
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | XUnit.prototype.test = function (test) {
|
127 | var attrs = {
|
128 | classname: test.parent.fullTitle(),
|
129 | name: test.title,
|
130 | time: (test.duration / 1000) || 0
|
131 | };
|
132 |
|
133 | if (test.state === 'failed') {
|
134 | var err = test.err;
|
135 | this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack))));
|
136 | } else if (test.isPending()) {
|
137 | this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
|
138 | } else {
|
139 | this.write(tag('testcase', attrs, true));
|
140 | }
|
141 | };
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 | function tag (name, attrs, close, content) {
|
153 | var end = close ? '/>' : '>';
|
154 | var pairs = [];
|
155 | var tag;
|
156 |
|
157 | for (var key in attrs) {
|
158 | if (Object.prototype.hasOwnProperty.call(attrs, key)) {
|
159 | pairs.push(key + '="' + escape(attrs[key]) + '"');
|
160 | }
|
161 | }
|
162 |
|
163 | tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
|
164 | if (content) {
|
165 | tag += content + '</' + name + end;
|
166 | }
|
167 | return tag;
|
168 | }
|