mocha 9.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +1015 -0
  2. package/LICENSE +22 -0
  3. package/README.md +70 -0
  4. package/assets/growl/error.png +0 -0
  5. package/assets/growl/ok.png +0 -0
  6. package/bin/_mocha +10 -0
  7. package/bin/mocha +142 -0
  8. package/browser-entry.js +216 -0
  9. package/index.js +3 -0
  10. package/lib/browser/growl.js +169 -0
  11. package/lib/browser/highlight-tags.js +39 -0
  12. package/lib/browser/parse-query.js +24 -0
  13. package/lib/browser/progress.js +123 -0
  14. package/lib/browser/template.html +20 -0
  15. package/lib/cli/cli.js +89 -0
  16. package/lib/cli/collect-files.js +92 -0
  17. package/lib/cli/commands.js +13 -0
  18. package/lib/cli/config.js +105 -0
  19. package/lib/cli/index.js +3 -0
  20. package/lib/cli/init.js +36 -0
  21. package/lib/cli/lookup-files.js +145 -0
  22. package/lib/cli/node-flags.js +85 -0
  23. package/lib/cli/one-and-dones.js +69 -0
  24. package/lib/cli/options.js +261 -0
  25. package/lib/cli/run-helpers.js +243 -0
  26. package/lib/cli/run-option-metadata.js +117 -0
  27. package/lib/cli/run.js +379 -0
  28. package/lib/cli/watch-run.js +380 -0
  29. package/lib/context.js +86 -0
  30. package/lib/errors.js +563 -0
  31. package/lib/hook.js +89 -0
  32. package/lib/interfaces/bdd.js +111 -0
  33. package/lib/interfaces/common.js +193 -0
  34. package/lib/interfaces/exports.js +60 -0
  35. package/lib/interfaces/index.js +6 -0
  36. package/lib/interfaces/qunit.js +98 -0
  37. package/lib/interfaces/tdd.js +106 -0
  38. package/lib/mocha.js +1374 -0
  39. package/lib/mocharc.json +10 -0
  40. package/lib/nodejs/buffered-worker-pool.js +172 -0
  41. package/lib/nodejs/esm-utils.js +109 -0
  42. package/lib/nodejs/file-unloader.js +15 -0
  43. package/lib/nodejs/growl.js +137 -0
  44. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  45. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  46. package/lib/nodejs/serializer.js +412 -0
  47. package/lib/nodejs/worker.js +151 -0
  48. package/lib/pending.js +16 -0
  49. package/lib/plugin-loader.js +286 -0
  50. package/lib/reporters/base.js +537 -0
  51. package/lib/reporters/doc.js +95 -0
  52. package/lib/reporters/dot.js +81 -0
  53. package/lib/reporters/html.js +390 -0
  54. package/lib/reporters/index.js +19 -0
  55. package/lib/reporters/json-stream.js +92 -0
  56. package/lib/reporters/json.js +162 -0
  57. package/lib/reporters/landing.js +116 -0
  58. package/lib/reporters/list.js +78 -0
  59. package/lib/reporters/markdown.js +112 -0
  60. package/lib/reporters/min.js +52 -0
  61. package/lib/reporters/nyan.js +276 -0
  62. package/lib/reporters/progress.js +104 -0
  63. package/lib/reporters/spec.js +99 -0
  64. package/lib/reporters/tap.js +293 -0
  65. package/lib/reporters/xunit.js +217 -0
  66. package/lib/runnable.js +476 -0
  67. package/lib/runner.js +1269 -0
  68. package/lib/stats-collector.js +83 -0
  69. package/lib/suite.js +695 -0
  70. package/lib/test.js +113 -0
  71. package/lib/utils.js +641 -0
  72. package/mocha-es2018.js +19816 -0
  73. package/mocha.css +325 -0
  74. package/mocha.js +30844 -0
  75. package/mocha.js.map +1 -0
  76. package/package.json +200 -0
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+ /**
3
+ * @module Progress
4
+ */
5
+ /**
6
+ * Module dependencies.
7
+ */
8
+
9
+ var Base = require('./base');
10
+ var constants = require('../runner').constants;
11
+ var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
12
+ var EVENT_TEST_END = constants.EVENT_TEST_END;
13
+ var EVENT_RUN_END = constants.EVENT_RUN_END;
14
+ var inherits = require('../utils').inherits;
15
+ var color = Base.color;
16
+ var cursor = Base.cursor;
17
+
18
+ /**
19
+ * Expose `Progress`.
20
+ */
21
+
22
+ exports = module.exports = Progress;
23
+
24
+ /**
25
+ * General progress bar color.
26
+ */
27
+
28
+ Base.colors.progress = 90;
29
+
30
+ /**
31
+ * Constructs a new `Progress` reporter instance.
32
+ *
33
+ * @public
34
+ * @class
35
+ * @memberof Mocha.reporters
36
+ * @extends Mocha.reporters.Base
37
+ * @param {Runner} runner - Instance triggers reporter actions.
38
+ * @param {Object} [options] - runner options
39
+ */
40
+ function Progress(runner, options) {
41
+ Base.call(this, runner, options);
42
+
43
+ var self = this;
44
+ var width = (Base.window.width * 0.5) | 0;
45
+ var total = runner.total;
46
+ var complete = 0;
47
+ var lastN = -1;
48
+
49
+ // default chars
50
+ options = options || {};
51
+ var reporterOptions = options.reporterOptions || {};
52
+
53
+ options.open = reporterOptions.open || '[';
54
+ options.complete = reporterOptions.complete || '▬';
55
+ options.incomplete = reporterOptions.incomplete || Base.symbols.dot;
56
+ options.close = reporterOptions.close || ']';
57
+ options.verbose = reporterOptions.verbose || false;
58
+
59
+ // tests started
60
+ runner.on(EVENT_RUN_BEGIN, function() {
61
+ process.stdout.write('\n');
62
+ cursor.hide();
63
+ });
64
+
65
+ // tests complete
66
+ runner.on(EVENT_TEST_END, function() {
67
+ complete++;
68
+
69
+ var percent = complete / total;
70
+ var n = (width * percent) | 0;
71
+ var i = width - n;
72
+
73
+ if (n === lastN && !options.verbose) {
74
+ // Don't re-render the line if it hasn't changed
75
+ return;
76
+ }
77
+ lastN = n;
78
+
79
+ cursor.CR();
80
+ process.stdout.write('\u001b[J');
81
+ process.stdout.write(color('progress', ' ' + options.open));
82
+ process.stdout.write(Array(n).join(options.complete));
83
+ process.stdout.write(Array(i).join(options.incomplete));
84
+ process.stdout.write(color('progress', options.close));
85
+ if (options.verbose) {
86
+ process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
87
+ }
88
+ });
89
+
90
+ // tests are complete, output some stats
91
+ // and the failures if any
92
+ runner.once(EVENT_RUN_END, function() {
93
+ cursor.show();
94
+ process.stdout.write('\n');
95
+ self.epilogue();
96
+ });
97
+ }
98
+
99
+ /**
100
+ * Inherit from `Base.prototype`.
101
+ */
102
+ inherits(Progress, Base);
103
+
104
+ Progress.description = 'a progress bar';
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+ /**
3
+ * @module Spec
4
+ */
5
+ /**
6
+ * Module dependencies.
7
+ */
8
+
9
+ var Base = require('./base');
10
+ var constants = require('../runner').constants;
11
+ var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
12
+ var EVENT_RUN_END = constants.EVENT_RUN_END;
13
+ var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
14
+ var EVENT_SUITE_END = constants.EVENT_SUITE_END;
15
+ var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
16
+ var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
17
+ var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
18
+ var inherits = require('../utils').inherits;
19
+ var color = Base.color;
20
+
21
+ /**
22
+ * Expose `Spec`.
23
+ */
24
+
25
+ exports = module.exports = Spec;
26
+
27
+ /**
28
+ * Constructs a new `Spec` reporter instance.
29
+ *
30
+ * @public
31
+ * @class
32
+ * @memberof Mocha.reporters
33
+ * @extends Mocha.reporters.Base
34
+ * @param {Runner} runner - Instance triggers reporter actions.
35
+ * @param {Object} [options] - runner options
36
+ */
37
+ function Spec(runner, options) {
38
+ Base.call(this, runner, options);
39
+
40
+ var self = this;
41
+ var indents = 0;
42
+ var n = 0;
43
+
44
+ function indent() {
45
+ return Array(indents).join(' ');
46
+ }
47
+
48
+ runner.on(EVENT_RUN_BEGIN, function() {
49
+ Base.consoleLog();
50
+ });
51
+
52
+ runner.on(EVENT_SUITE_BEGIN, function(suite) {
53
+ ++indents;
54
+ Base.consoleLog(color('suite', '%s%s'), indent(), suite.title);
55
+ });
56
+
57
+ runner.on(EVENT_SUITE_END, function() {
58
+ --indents;
59
+ if (indents === 1) {
60
+ Base.consoleLog();
61
+ }
62
+ });
63
+
64
+ runner.on(EVENT_TEST_PENDING, function(test) {
65
+ var fmt = indent() + color('pending', ' - %s');
66
+ Base.consoleLog(fmt, test.title);
67
+ });
68
+
69
+ runner.on(EVENT_TEST_PASS, function(test) {
70
+ var fmt;
71
+ if (test.speed === 'fast') {
72
+ fmt =
73
+ indent() +
74
+ color('checkmark', ' ' + Base.symbols.ok) +
75
+ color('pass', ' %s');
76
+ Base.consoleLog(fmt, test.title);
77
+ } else {
78
+ fmt =
79
+ indent() +
80
+ color('checkmark', ' ' + Base.symbols.ok) +
81
+ color('pass', ' %s') +
82
+ color(test.speed, ' (%dms)');
83
+ Base.consoleLog(fmt, test.title, test.duration);
84
+ }
85
+ });
86
+
87
+ runner.on(EVENT_TEST_FAIL, function(test) {
88
+ Base.consoleLog(indent() + color('fail', ' %d) %s'), ++n, test.title);
89
+ });
90
+
91
+ runner.once(EVENT_RUN_END, self.epilogue.bind(self));
92
+ }
93
+
94
+ /**
95
+ * Inherit from `Base.prototype`.
96
+ */
97
+ inherits(Spec, Base);
98
+
99
+ Spec.description = 'hierarchical & verbose [default]';
@@ -0,0 +1,293 @@
1
+ 'use strict';
2
+ /**
3
+ * @module TAP
4
+ */
5
+ /**
6
+ * Module dependencies.
7
+ */
8
+
9
+ var util = require('util');
10
+ var Base = require('./base');
11
+ var constants = require('../runner').constants;
12
+ var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
13
+ var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
14
+ var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;
15
+ var EVENT_RUN_END = constants.EVENT_RUN_END;
16
+ var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
17
+ var EVENT_TEST_END = constants.EVENT_TEST_END;
18
+ var inherits = require('../utils').inherits;
19
+ var sprintf = util.format;
20
+
21
+ /**
22
+ * Expose `TAP`.
23
+ */
24
+
25
+ exports = module.exports = TAP;
26
+
27
+ /**
28
+ * Constructs a new `TAP` reporter instance.
29
+ *
30
+ * @public
31
+ * @class
32
+ * @memberof Mocha.reporters
33
+ * @extends Mocha.reporters.Base
34
+ * @param {Runner} runner - Instance triggers reporter actions.
35
+ * @param {Object} [options] - runner options
36
+ */
37
+ function TAP(runner, options) {
38
+ Base.call(this, runner, options);
39
+
40
+ var self = this;
41
+ var n = 1;
42
+
43
+ var tapVersion = '12';
44
+ if (options && options.reporterOptions) {
45
+ if (options.reporterOptions.tapVersion) {
46
+ tapVersion = options.reporterOptions.tapVersion.toString();
47
+ }
48
+ }
49
+
50
+ this._producer = createProducer(tapVersion);
51
+
52
+ runner.once(EVENT_RUN_BEGIN, function() {
53
+ self._producer.writeVersion();
54
+ });
55
+
56
+ runner.on(EVENT_TEST_END, function() {
57
+ ++n;
58
+ });
59
+
60
+ runner.on(EVENT_TEST_PENDING, function(test) {
61
+ self._producer.writePending(n, test);
62
+ });
63
+
64
+ runner.on(EVENT_TEST_PASS, function(test) {
65
+ self._producer.writePass(n, test);
66
+ });
67
+
68
+ runner.on(EVENT_TEST_FAIL, function(test, err) {
69
+ self._producer.writeFail(n, test, err);
70
+ });
71
+
72
+ runner.once(EVENT_RUN_END, function() {
73
+ self._producer.writeEpilogue(runner.stats);
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Inherit from `Base.prototype`.
79
+ */
80
+ inherits(TAP, Base);
81
+
82
+ /**
83
+ * Returns a TAP-safe title of `test`.
84
+ *
85
+ * @private
86
+ * @param {Test} test - Test instance.
87
+ * @return {String} title with any hash character removed
88
+ */
89
+ function title(test) {
90
+ return test.fullTitle().replace(/#/g, '');
91
+ }
92
+
93
+ /**
94
+ * Writes newline-terminated formatted string to reporter output stream.
95
+ *
96
+ * @private
97
+ * @param {string} format - `printf`-like format string
98
+ * @param {...*} [varArgs] - Format string arguments
99
+ */
100
+ function println(format, varArgs) {
101
+ var vargs = Array.from(arguments);
102
+ vargs[0] += '\n';
103
+ process.stdout.write(sprintf.apply(null, vargs));
104
+ }
105
+
106
+ /**
107
+ * Returns a `tapVersion`-appropriate TAP producer instance, if possible.
108
+ *
109
+ * @private
110
+ * @param {string} tapVersion - Version of TAP specification to produce.
111
+ * @returns {TAPProducer} specification-appropriate instance
112
+ * @throws {Error} if specification version has no associated producer.
113
+ */
114
+ function createProducer(tapVersion) {
115
+ var producers = {
116
+ '12': new TAP12Producer(),
117
+ '13': new TAP13Producer()
118
+ };
119
+ var producer = producers[tapVersion];
120
+
121
+ if (!producer) {
122
+ throw new Error(
123
+ 'invalid or unsupported TAP version: ' + JSON.stringify(tapVersion)
124
+ );
125
+ }
126
+
127
+ return producer;
128
+ }
129
+
130
+ /**
131
+ * @summary
132
+ * Constructs a new TAPProducer.
133
+ *
134
+ * @description
135
+ * <em>Only</em> to be used as an abstract base class.
136
+ *
137
+ * @private
138
+ * @constructor
139
+ */
140
+ function TAPProducer() {}
141
+
142
+ /**
143
+ * Writes the TAP version to reporter output stream.
144
+ *
145
+ * @abstract
146
+ */
147
+ TAPProducer.prototype.writeVersion = function() {};
148
+
149
+ /**
150
+ * Writes the plan to reporter output stream.
151
+ *
152
+ * @abstract
153
+ * @param {number} ntests - Number of tests that are planned to run.
154
+ */
155
+ TAPProducer.prototype.writePlan = function(ntests) {
156
+ println('%d..%d', 1, ntests);
157
+ };
158
+
159
+ /**
160
+ * Writes that test passed to reporter output stream.
161
+ *
162
+ * @abstract
163
+ * @param {number} n - Index of test that passed.
164
+ * @param {Test} test - Instance containing test information.
165
+ */
166
+ TAPProducer.prototype.writePass = function(n, test) {
167
+ println('ok %d %s', n, title(test));
168
+ };
169
+
170
+ /**
171
+ * Writes that test was skipped to reporter output stream.
172
+ *
173
+ * @abstract
174
+ * @param {number} n - Index of test that was skipped.
175
+ * @param {Test} test - Instance containing test information.
176
+ */
177
+ TAPProducer.prototype.writePending = function(n, test) {
178
+ println('ok %d %s # SKIP -', n, title(test));
179
+ };
180
+
181
+ /**
182
+ * Writes that test failed to reporter output stream.
183
+ *
184
+ * @abstract
185
+ * @param {number} n - Index of test that failed.
186
+ * @param {Test} test - Instance containing test information.
187
+ * @param {Error} err - Reason the test failed.
188
+ */
189
+ TAPProducer.prototype.writeFail = function(n, test, err) {
190
+ println('not ok %d %s', n, title(test));
191
+ };
192
+
193
+ /**
194
+ * Writes the summary epilogue to reporter output stream.
195
+ *
196
+ * @abstract
197
+ * @param {Object} stats - Object containing run statistics.
198
+ */
199
+ TAPProducer.prototype.writeEpilogue = function(stats) {
200
+ // :TBD: Why is this not counting pending tests?
201
+ println('# tests ' + (stats.passes + stats.failures));
202
+ println('# pass ' + stats.passes);
203
+ // :TBD: Why are we not showing pending results?
204
+ println('# fail ' + stats.failures);
205
+ this.writePlan(stats.passes + stats.failures + stats.pending);
206
+ };
207
+
208
+ /**
209
+ * @summary
210
+ * Constructs a new TAP12Producer.
211
+ *
212
+ * @description
213
+ * Produces output conforming to the TAP12 specification.
214
+ *
215
+ * @private
216
+ * @constructor
217
+ * @extends TAPProducer
218
+ * @see {@link https://testanything.org/tap-specification.html|Specification}
219
+ */
220
+ function TAP12Producer() {
221
+ /**
222
+ * Writes that test failed to reporter output stream, with error formatting.
223
+ * @override
224
+ */
225
+ this.writeFail = function(n, test, err) {
226
+ TAPProducer.prototype.writeFail.call(this, n, test, err);
227
+ if (err.message) {
228
+ println(err.message.replace(/^/gm, ' '));
229
+ }
230
+ if (err.stack) {
231
+ println(err.stack.replace(/^/gm, ' '));
232
+ }
233
+ };
234
+ }
235
+
236
+ /**
237
+ * Inherit from `TAPProducer.prototype`.
238
+ */
239
+ inherits(TAP12Producer, TAPProducer);
240
+
241
+ /**
242
+ * @summary
243
+ * Constructs a new TAP13Producer.
244
+ *
245
+ * @description
246
+ * Produces output conforming to the TAP13 specification.
247
+ *
248
+ * @private
249
+ * @constructor
250
+ * @extends TAPProducer
251
+ * @see {@link https://testanything.org/tap-version-13-specification.html|Specification}
252
+ */
253
+ function TAP13Producer() {
254
+ /**
255
+ * Writes the TAP version to reporter output stream.
256
+ * @override
257
+ */
258
+ this.writeVersion = function() {
259
+ println('TAP version 13');
260
+ };
261
+
262
+ /**
263
+ * Writes that test failed to reporter output stream, with error formatting.
264
+ * @override
265
+ */
266
+ this.writeFail = function(n, test, err) {
267
+ TAPProducer.prototype.writeFail.call(this, n, test, err);
268
+ var emitYamlBlock = err.message != null || err.stack != null;
269
+ if (emitYamlBlock) {
270
+ println(indent(1) + '---');
271
+ if (err.message) {
272
+ println(indent(2) + 'message: |-');
273
+ println(err.message.replace(/^/gm, indent(3)));
274
+ }
275
+ if (err.stack) {
276
+ println(indent(2) + 'stack: |-');
277
+ println(err.stack.replace(/^/gm, indent(3)));
278
+ }
279
+ println(indent(1) + '...');
280
+ }
281
+ };
282
+
283
+ function indent(level) {
284
+ return Array(level + 1).join(' ');
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Inherit from `TAPProducer.prototype`.
290
+ */
291
+ inherits(TAP13Producer, TAPProducer);
292
+
293
+ TAP.description = 'TAP-compatible output';
@@ -0,0 +1,217 @@
1
+ 'use strict';
2
+ /**
3
+ * @module XUnit
4
+ */
5
+ /**
6
+ * Module dependencies.
7
+ */
8
+
9
+ var Base = require('./base');
10
+ var utils = require('../utils');
11
+ var fs = require('fs');
12
+ var path = require('path');
13
+ var errors = require('../errors');
14
+ var createUnsupportedError = errors.createUnsupportedError;
15
+ var constants = require('../runner').constants;
16
+ var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
17
+ var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
18
+ var EVENT_RUN_END = constants.EVENT_RUN_END;
19
+ var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
20
+ var STATE_FAILED = require('../runnable').constants.STATE_FAILED;
21
+ var inherits = utils.inherits;
22
+ var escape = utils.escape;
23
+
24
+ /**
25
+ * Save timer references to avoid Sinon interfering (see GH-237).
26
+ */
27
+ var Date = global.Date;
28
+
29
+ /**
30
+ * Expose `XUnit`.
31
+ */
32
+
33
+ exports = module.exports = XUnit;
34
+
35
+ /**
36
+ * Constructs a new `XUnit` reporter instance.
37
+ *
38
+ * @public
39
+ * @class
40
+ * @memberof Mocha.reporters
41
+ * @extends Mocha.reporters.Base
42
+ * @param {Runner} runner - Instance triggers reporter actions.
43
+ * @param {Object} [options] - runner options
44
+ */
45
+ function XUnit(runner, options) {
46
+ Base.call(this, runner, options);
47
+
48
+ var stats = this.stats;
49
+ var tests = [];
50
+ var self = this;
51
+
52
+ // the name of the test suite, as it will appear in the resulting XML file
53
+ var suiteName;
54
+
55
+ // the default name of the test suite if none is provided
56
+ var DEFAULT_SUITE_NAME = 'Mocha Tests';
57
+
58
+ if (options && options.reporterOptions) {
59
+ if (options.reporterOptions.output) {
60
+ if (!fs.createWriteStream) {
61
+ throw createUnsupportedError('file output not supported in browser');
62
+ }
63
+
64
+ fs.mkdirSync(path.dirname(options.reporterOptions.output), {
65
+ recursive: true
66
+ });
67
+ self.fileStream = fs.createWriteStream(options.reporterOptions.output);
68
+ }
69
+
70
+ // get the suite name from the reporter options (if provided)
71
+ suiteName = options.reporterOptions.suiteName;
72
+ }
73
+
74
+ // fall back to the default suite name
75
+ suiteName = suiteName || DEFAULT_SUITE_NAME;
76
+
77
+ runner.on(EVENT_TEST_PENDING, function(test) {
78
+ tests.push(test);
79
+ });
80
+
81
+ runner.on(EVENT_TEST_PASS, function(test) {
82
+ tests.push(test);
83
+ });
84
+
85
+ runner.on(EVENT_TEST_FAIL, function(test) {
86
+ tests.push(test);
87
+ });
88
+
89
+ runner.once(EVENT_RUN_END, function() {
90
+ self.write(
91
+ tag(
92
+ 'testsuite',
93
+ {
94
+ name: suiteName,
95
+ tests: stats.tests,
96
+ failures: 0,
97
+ errors: stats.failures,
98
+ skipped: stats.tests - stats.failures - stats.passes,
99
+ timestamp: new Date().toUTCString(),
100
+ time: stats.duration / 1000 || 0
101
+ },
102
+ false
103
+ )
104
+ );
105
+
106
+ tests.forEach(function(t) {
107
+ self.test(t);
108
+ });
109
+
110
+ self.write('</testsuite>');
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Inherit from `Base.prototype`.
116
+ */
117
+ inherits(XUnit, Base);
118
+
119
+ /**
120
+ * Override done to close the stream (if it's a file).
121
+ *
122
+ * @param failures
123
+ * @param {Function} fn
124
+ */
125
+ XUnit.prototype.done = function(failures, fn) {
126
+ if (this.fileStream) {
127
+ this.fileStream.end(function() {
128
+ fn(failures);
129
+ });
130
+ } else {
131
+ fn(failures);
132
+ }
133
+ };
134
+
135
+ /**
136
+ * Write out the given line.
137
+ *
138
+ * @param {string} line
139
+ */
140
+ XUnit.prototype.write = function(line) {
141
+ if (this.fileStream) {
142
+ this.fileStream.write(line + '\n');
143
+ } else if (typeof process === 'object' && process.stdout) {
144
+ process.stdout.write(line + '\n');
145
+ } else {
146
+ Base.consoleLog(line);
147
+ }
148
+ };
149
+
150
+ /**
151
+ * Output tag for the given `test.`
152
+ *
153
+ * @param {Test} test
154
+ */
155
+ XUnit.prototype.test = function(test) {
156
+ Base.useColors = false;
157
+
158
+ var attrs = {
159
+ classname: test.parent.fullTitle(),
160
+ name: test.title,
161
+ time: test.duration / 1000 || 0
162
+ };
163
+
164
+ if (test.state === STATE_FAILED) {
165
+ var err = test.err;
166
+ var diff =
167
+ !Base.hideDiff && Base.showDiff(err)
168
+ ? '\n' + Base.generateDiff(err.actual, err.expected)
169
+ : '';
170
+ this.write(
171
+ tag(
172
+ 'testcase',
173
+ attrs,
174
+ false,
175
+ tag(
176
+ 'failure',
177
+ {},
178
+ false,
179
+ escape(err.message) + escape(diff) + '\n' + escape(err.stack)
180
+ )
181
+ )
182
+ );
183
+ } else if (test.isPending()) {
184
+ this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
185
+ } else {
186
+ this.write(tag('testcase', attrs, true));
187
+ }
188
+ };
189
+
190
+ /**
191
+ * HTML tag helper.
192
+ *
193
+ * @param name
194
+ * @param attrs
195
+ * @param close
196
+ * @param content
197
+ * @return {string}
198
+ */
199
+ function tag(name, attrs, close, content) {
200
+ var end = close ? '/>' : '>';
201
+ var pairs = [];
202
+ var tag;
203
+
204
+ for (var key in attrs) {
205
+ if (Object.prototype.hasOwnProperty.call(attrs, key)) {
206
+ pairs.push(key + '="' + escape(attrs[key]) + '"');
207
+ }
208
+ }
209
+
210
+ tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
211
+ if (content) {
212
+ tag += content + '</' + name + end;
213
+ }
214
+ return tag;
215
+ }
216
+
217
+ XUnit.description = 'XUnit-compatible XML output';