Skip to content

Commit

Permalink
Merge branch 'release/2.0.4' [ci skip]
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Gruber committed Feb 20, 2017
2 parents e4c601f + 9f8530a commit 5c04cc8
Show file tree
Hide file tree
Showing 10 changed files with 1,420 additions and 589 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#Changelog

###2.0.4
- Better handling of different coding styles in test code. [#98](https://github.com/adamgruber/mochawesome/issues/98)
- Separate utility functions from main reporter code for better test coverage
- Bump `mochawesome-report-generator` and `fs-extra` packages

###2.0.3
- Fixed [#126](https://github.com/adamgruber/mochawesome/issues/126)
- Fix default options handling
Expand Down
275 changes: 15 additions & 260 deletions dist/mochawesome.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var _promise = require('babel-runtime/core-js/promise');

var _promise2 = _interopRequireDefault(_promise);

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

/**
* Done function gets called before mocha exits
*
Expand Down Expand Up @@ -79,260 +71,23 @@ var done = function () {

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var fs = require('fs-extra');
var mocha = require('mocha');
var mochaUtils = require('mocha/lib/utils');
var _ = require('lodash');
var uuid = require('uuid');
var chalk = require('chalk');
var stringify = require('json-stringify-safe');
var conf = require('./config');
var diff = require('diff');
var marge = require('mochawesome-report-generator');
var utils = require('./utils');

// Track the total number of tests registered
var totalTestsRegistered = void 0;

/**
* HELPER FUNCTIONS
*/

function log(msg, level, config) {
// Don't log messages in quiet mode
if (config && config.quiet) return;
var logMethod = console[level] || console.log;
var out = msg;
if ((typeof msg === 'undefined' ? 'undefined' : (0, _typeof3.default)(msg)) === 'object') {
out = stringify(msg, null, 2);
}
logMethod('[' + chalk.gray('mochawesome') + '] ' + out + '\n');
}

/**
* Return a classname based on percentage
*
* @param {Integer} pct
* @api private
*/

function _getPercentClass(pct) {
if (pct <= 50) {
return 'danger';
} else if (pct > 50 && pct < 80) {
return 'warning';
} else {
return 'success';
}
}

/**
* Remove all properties from an object except
* those that are in the propsToKeep array.
*
* @param {Object} obj
* @param {Array} propsToKeep
* @api private
*/

function removeAllPropsFromObjExcept(obj, propsToKeep) {
_.forOwn(obj, function (val, prop) {
if (propsToKeep.indexOf(prop) === -1) {
delete obj[prop];
}
});
}

/**
* Check that a / b have the same type.
*
* @param {Object} a
* @param {Object} b
* @return {boolean}
*/
function sameType(a, b) {
var objToString = Object.prototype.toString;
return objToString.call(a) === objToString.call(b);
}

/**
* Strip the function definition from `str`,
* and re-indent for pre whitespace.
*/

function cleanCode(str) {
str = str.replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '').replace(/^function *\(.*\) *{|\(.*\) *=> *{?/, '').replace(/\s+\}$/, '');

var spaces = str.match(/^\n?( *)/)[1].length;
var tabs = str.match(/^\n?(\t*)/)[1].length;
/* istanbul ignore next */
var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}', 'gm');

str = str.replace(re, '');
str = str.replace(/^\s+|\s+$/g, '');
return str;
}
// Import the utility functions
var log = utils.log,
getPercentClass = utils.getPercentClass,
cleanTest = utils.cleanTest,
traverseSuites = utils.traverseSuites,
saveFile = utils.saveFile;

/**
* Return a plain-object representation of `test`
* free of cyclic properties etc.
*
* @param {Object} test
* @return {Object}
* @api private
*/

function cleanTest(test) {
/* istanbul ignore next: test.fn exists prior to mocha 2.4.0 */
var code = test.fn ? test.fn.toString() : test.body;
var err = test.err || {};
var actual = err.actual,
expected = err.expected,
showDiff = err.showDiff,
stack = err.stack;


if (code) {
code = cleanCode(code);
}

if (stack) {
err.estack = err.stack;
}

// Create diff for the error
if (showDiff !== false && sameType(actual, expected) && expected !== undefined) {
/* istanbul ignore if */
if (!(_.isString(actual) && _.isString(expected))) {
err.actual = mochaUtils.stringify(actual);
err.expected = mochaUtils.stringify(expected);
}
err.diff = diff.createPatch('string', err.actual, err.expected).split('\n').splice(4).map(function (line) {
if (line.match(/@@/)) {
return null;
}
if (line.match(/\\ No newline/)) {
return null;
}
return line.replace(/^(-|\+)/, '$1 ');
}).filter(function (line) {
return typeof line !== 'undefined' && line !== null;
}).join('\n');
}

var cleaned = {
title: test.title,
fullTitle: _.isFunction(test.fullTitle) ? test.fullTitle() : /* istanbul ignore next */test.title,
timedOut: test.timedOut,
duration: test.duration || 0,
state: test.state,
speed: test.speed,
pass: test.state === 'passed',
fail: test.state === 'failed',
pending: test.pending,
context: stringify(test.context, null, 2),
code: code,
err: err,
isRoot: test.parent && test.parent.root,
uuid: test.uuid || /* istanbul ignore next: default */uuid.v4(),
parentUUID: test.parent && test.parent.uuid
};

cleaned.skipped = !cleaned.pass && !cleaned.fail && !cleaned.pending;

return cleaned;
}

/**
* Modify the suite object to add properties needed to render
* the template and remove properties we do not need.
*
* @param {Object} suite
* @api private
*/

function cleanSuite(suite) {
suite.uuid = uuid.v4();

var cleanTests = _.map(suite.tests, cleanTest);
var passingTests = _.filter(cleanTests, { state: 'passed' });
var failingTests = _.filter(cleanTests, { state: 'failed' });
var pendingTests = _.filter(cleanTests, { pending: true });
var skippedTests = _.filter(cleanTests, { skipped: true });
var duration = 0;

_.each(cleanTests, function (test) {
duration += test.duration;
});

totalTestsRegistered += suite.tests.length;

suite.tests = cleanTests;
suite.fullFile = suite.file || '';
suite.file = suite.file ? suite.file.replace(process.cwd(), '') : '';
suite.passes = passingTests;
suite.failures = failingTests;
suite.pending = pendingTests;
suite.skipped = skippedTests;
suite.hasTests = suite.tests.length > 0;
suite.hasSuites = suite.suites.length > 0;
suite.totalTests = suite.tests.length;
suite.totalPasses = passingTests.length;
suite.totalFailures = failingTests.length;
suite.totalPending = pendingTests.length;
suite.totalSkipped = skippedTests.length;
suite.hasPasses = passingTests.length > 0;
suite.hasFailures = failingTests.length > 0;
suite.hasPending = pendingTests.length > 0;
suite.hasSkipped = suite.skipped.length > 0;
suite.duration = duration;

if (suite.root) {
suite.rootEmpty = suite.totalTests === 0;
}

removeAllPropsFromObjExcept(suite, ['title', 'fullFile', 'file', 'tests', 'suites', 'passes', 'failures', 'pending', 'skipped', 'hasTests', 'hasSuites', 'totalTests', 'totalPasses', 'totalFailures', 'totalPending', 'totalSkipped', 'hasPasses', 'hasFailures', 'hasPending', 'hasSkipped', 'root', 'uuid', 'duration', 'rootEmpty', '_timeout']);
}

/**
* Do a breadth-first search to find
* and format all nested 'suite' objects.
*
* @param {Object} suite
* @api private
*/

function traverseSuites(suite) {
var queue = [];
var next = suite;
while (next) {
if (next.root) {
cleanSuite(next);
}
if (next.suites.length) {
_.each(next.suites, function (nextSuite, i) {
cleanSuite(nextSuite);
queue.push(nextSuite);
});
}
next = queue.shift();
}
}

/**
* Saves a file
*
* @param {String} filename
* @param {String} data
* @returns {Promise}
*/
// Track the total number of tests registered

function saveFile(filename, data) {
return new _promise2.default(function (resolve, reject) {
fs.outputFile(filename, data, function (err) {
return err === null ? resolve(true) : reject(err);
});
});
}function Mochawesome(runner, options) {
var totalTestsRegistered = { total: 0 };function Mochawesome(runner, options) {
var _this = this;

// Done function will be called before mocha exits
Expand All @@ -342,7 +97,7 @@ function saveFile(filename, data) {
};

// Reset total tests counter
totalTestsRegistered = 0;
totalTestsRegistered.total = 0;

// Create/Save necessary report dirs/files
var reporterOpts = options && options.reporterOptions || {};
Expand Down Expand Up @@ -397,7 +152,7 @@ function saveFile(filename, data) {

var allSuites = _this.runner.suite;

traverseSuites(allSuites);
traverseSuites(allSuites, totalTestsRegistered);

var obj = {
stats: _this.stats,
Expand All @@ -409,7 +164,7 @@ function saveFile(filename, data) {
copyrightYear: new Date().getFullYear()
};

obj.stats.testsRegistered = totalTestsRegistered;
obj.stats.testsRegistered = totalTestsRegistered.total;

var _obj$stats = obj.stats,
passes = _obj$stats.passes,
Expand All @@ -428,8 +183,8 @@ function saveFile(filename, data) {
obj.stats.skipped = testsRegistered - tests;
obj.stats.hasSkipped = obj.stats.skipped > 0;
obj.stats.failures -= obj.stats.other;
obj.stats.passPercentClass = _getPercentClass(passPercentage);
obj.stats.pendingPercentClass = _getPercentClass(pendingPercentage);
obj.stats.passPercentClass = getPercentClass(passPercentage);
obj.stats.pendingPercentClass = getPercentClass(pendingPercentage);

// Save the final output to be used in the done function
_this.output = stringify(obj, null, 2);
Expand All @@ -438,7 +193,7 @@ function saveFile(filename, data) {
// required because thrown errors are not handled directly in the
// event emitter pattern and mocha does not have an "on error"
/* istanbul ignore next */
console.error('Problem with mochawesome: ' + e.stack);
log('Problem with mochawesome: ' + e.stack, 'error');
}
});
}
Expand Down
Loading

0 comments on commit 5c04cc8

Please sign in to comment.