Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Gruber committed Jul 12, 2014
0 parents commit d687633
Show file tree
Hide file tree
Showing 12 changed files with 451 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz

pids
logs
results

node_modules

reports

npm-debug.log
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mochawesome
========================

1. Clone
2. `npm install`
3. `npm link`
4. `npm link mochawesome`
5. `gulp`
7 changes: 7 additions & 0 deletions fiveby-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"implicitWait": 5000,
"hubUrl": null,
"browsers": {
"chrome": 1
}
}
13 changes: 13 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//TODO: feeding in configs, logins, selenium servers, browsers.. tests should do this so they can run in isolation but that's a lot more maintenance...
var gulp = require('gulp');
var mocha = require('gulp-spawn-mocha');
var options = {reporter: 'mochawesome', timeout: 30000, slow: 1};


gulp.task('test', function () {
return gulp.src('test/*.js')
.pipe(mocha(options))
.on("error", console.warn.bind(console));
});

gulp.task('default', ['test']);
6 changes: 6 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Export lib/
*
*/

module.exports = require('./lib');
184 changes: 184 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
var util = require('util'),
fs = require('fs'),
path = require('path'),
mocha = require('mocha'),
_ = require('lodash'),
hogan = require('hogan.js'),
moment = require('moment');

var Base = mocha.reporters.Base,
utils = mocha.utils,
cursor = Base.cursor,
color = Base.color;

var reportsDir = path.join(process.cwd(), 'reports'),
reportJsonFile = path.join(reportsDir, 'reports.json'),
reportHtmlFile = path.join(reportsDir, 'reportCard.html');

module.exports = Mochawesome;

// Load template
var reportCard = fs.readFileSync(path.join(__dirname, '..', 'templates', 'reportCard.mu'), {
encoding: 'utf8'
});

// Compile template
var reportCardTmp = hogan.compile(reportCard);

/**
* Initialize a new reporter.
*
* @param {Runner} runner
* @api public
*/

function Mochawesome (runner) {
var self = this;
Base.call(this, runner);

var allSuites = {},
allTests = [],
allFailures = [],
allPasses = [];

runner.on('suite', function (suite) {
// ignore the root suite
if (!suite.root) {
// top level suite
if (suite.parent.root) {
allSuites[suite.title] = {};
}

// nested suite 1 level deep only
if (!suite.parent.root && suite.parent.parent.root) {
parentSuite = allSuites[suite.parent.title];
if (!parentSuite.childSuites) {
parentSuite.childSuites = {};
}
parentSuite.childSuites[suite.title] = {};
}
}
});

runner.on('suite end', function (suite) {
// ignore the root suite
if (!suite.root) {

var allTests = suite.tests.map(cleanTest);

var passingTests = allTests.filter(function (test) {
return test.state === 'passed';
});

var failingTests = allTests.filter(function (test) {
return test.state === 'failed';
});

var suiteObj = {
title: suite.title,
fullTitle: suite.fullTitle(),
tests: allTests,
passes: passingTests,
failures: failingTests,
totalTests: suite.tests.length,
totalPasses: passingTests.length,
totalFailures: failingTests.length
};

// top level suite
if (suite.parent.root) {
allSuites[suite.title] = _.merge(allSuites[suite.title], suiteObj);
}

// nested suite 1 level deep only
if (!suite.parent.root && suite.parent.parent.root) {
parentSuite = allSuites[suite.parent.title];
parentSuite.childSuites[suite.title] = suiteObj;
}
}
});

runner.on('test end', function (test) {
allTests.push(test);
});

runner.on('pass', function (test) {
allPasses.push(test);
});

runner.on('fail', function (test){
allFailures.push(test);
});

runner.on('end', function () {

// unless we render client-side, this has to be updated client-side
// self.stats.endDateStr = moment(self.stats.end).fromNow();

var obj = {
stats: self.stats,
suites: allSuites,
tests: allTests.map(cleanTest),
passes: allPasses.map(cleanTest),
failures: allFailures.map(cleanTest)
};

saveToFile('json', obj);
saveToFile('html', obj);
});
}

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

function cleanTest (test) {
return {
title: test.title,
fullTitle: test.fullTitle(),
duration: test.duration,
state: test.state,
pass: test.state === 'passed',
fail: test.state === 'failed',
file: test.file,
code: utils.clean(test.fn.toString()),
err: test.err
}
}

/**
* Save data out to files
*/

function saveToFile (filetype, inData) {
var outData, outFile, writeFile;
switch (filetype) {
case 'json':
outData = JSON.stringify(inData, null, 2);
outFile = reportJsonFile;
break;
case 'html':
outData = reportCardTmp.render(inData);
outFile = reportHtmlFile;
break;
}

try {
if (!fs.existsSync(reportsDir)) {
fs.mkdirSync(reportsDir);
};
writeFile = fs.openSync(outFile, 'w');
fs.writeSync(writeFile, outData);
fs.close(writeFile);
util.print("\nSaved " + outFile + "\n");
} catch (err) {
console.log(err);
util.print("\nError: Unable to save " + outFile + "\n");
}

}
34 changes: 34 additions & 0 deletions lib/sample-report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"allSuites" = {
"suite 1": {
"title": "suite title",
"fullTitle": "suite full title",
"tests": [{}, {}, {}],
"passes": [{}, {}],
"failures": [{}],
"totalTests": 3,
"totalPasses": 2,
"totalFailures": 1,
"childSuites": {
"child1": {
"title": "test title",
"fullTitle": "test full title",
"tests": [{}, {}, {}],
"passes": [{}, {}],
"failures": [{}],
"totalTests": 3,
"totalPasses": 2,
"totalFailures": 1
},
"child2": {
"title": "test title",
"fullTitle": "test full title",
"tests": [{}, {}, {}],
"passes": [{}, {}],
"failures": [{}],
"totalTests": 3,
"totalPasses": 2,
"totalFailures": 1
}
}
}
}
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "mochawesome",
"description": "An awesome mocha json html file reporter",
"author": "Adam Gruber <adam.gruber@dowjones.com>",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"hogan.js": "^3.0.2",
"lodash": "^2.4.1",
"mocha": "",
"moment": "^2.7.0"
},
"devDependencies": {
"fiveby": "git+https://github.dowjones.net/institutional/fiveby.git",
"gulp": "^3.8.1",
"gulp-spawn-mocha": "^0.1.5",
"should": "^3.3.2",
"mochawesome": ""
},
"scripts": {
"test": "mocha"
},
"engine": "node >= 0.8.0",
"keywords": [
"mocha",
"reporter",
"json",
"mustache"
],
"license": "ISC"
}
68 changes: 68 additions & 0 deletions templates/reportCard.mu
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mocha Report Card</title>
<link href='http://fonts.googleapis.com/css?family=Dosis:300,400,600,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<style>
body {
font-family: 'Dosis', sans-serif;
}
.suite {
}
</style>
</head>
<body>
<!-- NAVBAR -->
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">fiveby test report</a>
</div>
</div>
</div>

<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron hidden">
<div class="container">
<h1>Test Summary</h1>
{{#stats}}
<h3>Suites: {{suites}}</h3>
<h3>Tests: {{tests}}</h3>
<h3>Passes: {{passes}}</h3>
<h3>Failures: {{failures}}</h3>
<h3>Duration: {{duration}}</h3>
{{/stats}}
</div>
</div>

<div class="container">
{{#suites}}
<div class="suite panel">
<h2>{{title}}</h2>
<h5>{{endDateStr}}</h5>
{{#tests}}
<div class="test">
<h3><span class="glyphicon glyphicon-{{#pass}}ok text-success{{/pass}}{{#fail}}remove text-danger{{/fail}}"></span> {{title}}</h3>
<h4>{{file}}</h4>
<h4>Duration: {{duration}}ms</h4>
<pre><code>{{code}}</code></pre>
{{err}}
{{#err}}
Expected:{{expected}}
Actual:{{actual}}
Message:{{message}}
<pre class="bg-danger small">{{stack}}</pre>
{{/err}}
</div>
{{/tests}}
</div>
{{/suites}}
</div> <!-- /container -->


</body>
</html>
Loading

0 comments on commit d687633

Please sign in to comment.