123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- 'use strict';
- /**
- * @module XUnit
- */
- /**
- * Module dependencies.
- */
- var Base = require('./base');
- var utils = require('../utils');
- var inherits = utils.inherits;
- var fs = require('fs');
- var escape = utils.escape;
- var mkdirp = require('mkdirp');
- var path = require('path');
- /**
- * Save timer references to avoid Sinon interfering (see GH-237).
- */
- /* eslint-disable no-unused-vars, no-native-reassign */
- var Date = global.Date;
- var setTimeout = global.setTimeout;
- var setInterval = global.setInterval;
- var clearTimeout = global.clearTimeout;
- var clearInterval = global.clearInterval;
- /* eslint-enable no-unused-vars, no-native-reassign */
- /**
- * Expose `XUnit`.
- */
- exports = module.exports = XUnit;
- /**
- * Initialize a new `XUnit` reporter.
- *
- * @public
- * @class
- * @memberof Mocha.reporters
- * @extends Mocha.reporters.Base
- * @api public
- * @param {Runner} runner
- */
- function XUnit(runner, options) {
- Base.call(this, runner);
- var stats = this.stats;
- var tests = [];
- var self = this;
- // the name of the test suite, as it will appear in the resulting XML file
- var suiteName;
- // the default name of the test suite if none is provided
- var DEFAULT_SUITE_NAME = 'Mocha Tests';
- if (options && options.reporterOptions) {
- if (options.reporterOptions.output) {
- if (!fs.createWriteStream) {
- throw new Error('file output not supported in browser');
- }
- mkdirp.sync(path.dirname(options.reporterOptions.output));
- self.fileStream = fs.createWriteStream(options.reporterOptions.output);
- }
- // get the suite name from the reporter options (if provided)
- suiteName = options.reporterOptions.suiteName;
- }
- // fall back to the default suite name
- suiteName = suiteName || DEFAULT_SUITE_NAME;
- runner.on('pending', function(test) {
- tests.push(test);
- });
- runner.on('pass', function(test) {
- tests.push(test);
- });
- runner.on('fail', function(test) {
- tests.push(test);
- });
- runner.once('end', function() {
- self.write(
- tag(
- 'testsuite',
- {
- name: suiteName,
- tests: stats.tests,
- failures: stats.failures,
- errors: stats.failures,
- skipped: stats.tests - stats.failures - stats.passes,
- timestamp: new Date().toUTCString(),
- time: stats.duration / 1000 || 0
- },
- false
- )
- );
- tests.forEach(function(t) {
- self.test(t);
- });
- self.write('</testsuite>');
- });
- }
- /**
- * Inherit from `Base.prototype`.
- */
- inherits(XUnit, Base);
- /**
- * Override done to close the stream (if it's a file).
- *
- * @param failures
- * @param {Function} fn
- */
- XUnit.prototype.done = function(failures, fn) {
- if (this.fileStream) {
- this.fileStream.end(function() {
- fn(failures);
- });
- } else {
- fn(failures);
- }
- };
- /**
- * Write out the given line.
- *
- * @param {string} line
- */
- XUnit.prototype.write = function(line) {
- if (this.fileStream) {
- this.fileStream.write(line + '\n');
- } else if (typeof process === 'object' && process.stdout) {
- process.stdout.write(line + '\n');
- } else {
- console.log(line);
- }
- };
- /**
- * Output tag for the given `test.`
- *
- * @param {Test} test
- */
- XUnit.prototype.test = function(test) {
- var attrs = {
- classname: test.parent.fullTitle(),
- name: test.title,
- time: test.duration / 1000 || 0
- };
- if (test.state === 'failed') {
- var err = test.err;
- this.write(
- tag(
- 'testcase',
- attrs,
- false,
- tag(
- 'failure',
- {},
- false,
- escape(err.message) + '\n' + escape(err.stack)
- )
- )
- );
- } else if (test.isPending()) {
- this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
- } else {
- this.write(tag('testcase', attrs, true));
- }
- };
- /**
- * HTML tag helper.
- *
- * @param name
- * @param attrs
- * @param close
- * @param content
- * @return {string}
- */
- function tag(name, attrs, close, content) {
- var end = close ? '/>' : '>';
- var pairs = [];
- var tag;
- for (var key in attrs) {
- if (Object.prototype.hasOwnProperty.call(attrs, key)) {
- pairs.push(key + '="' + escape(attrs[key]) + '"');
- }
- }
- tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
- if (content) {
- tag += content + '</' + name + end;
- }
- return tag;
- }
|