Skip to content

Instantly share code, notes, and snippets.

@goriol
Last active August 29, 2015 14:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goriol/f1bed747658e2a27f4c0 to your computer and use it in GitHub Desktop.
Save goriol/f1bed747658e2a27f4c0 to your computer and use it in GitHub Desktop.
HTML formatter for Cucumber.js
function Configuration(argv) {
var Cucumber = require('../../cucumber');
var argumentParser = Cucumber.Cli.ArgumentParser(argv);
argumentParser.parse();
var self = {
getFormatter: function getFormatter() {
var formatter;
var format = argumentParser.getFormat();
var options = {
coffeeScriptSnippets: self.shouldSnippetsBeInCoffeeScript(),
snippets: self.shouldSnippetsBeShown()
};
switch(format) {
case Configuration.JSON_FORMAT_NAME:
formatter = Cucumber.Listener.JsonFormatter(options);
break;
case Configuration.PROGRESS_FORMAT_NAME:
formatter = Cucumber.Listener.ProgressFormatter(options);
break;
case Configuration.PRETTY_FORMAT_NAME:
formatter = Cucumber.Listener.PrettyFormatter(options);
break;
case Configuration.SUMMARY_FORMAT_NAME:
formatter = Cucumber.Listener.SummaryFormatter(options);
break;
case Configuration.HTML_FORMAT_NAME:
formatter = Cucumber.Listener.HtmlFormatter(options);
break;
default:
throw new Error('Unknown formatter name "' + format + '".');
}
return formatter;
},
getFeatureSources: function getFeatureSources() {
var featureFilePaths = argumentParser.getFeatureFilePaths();
var featureSourceLoader = Cucumber.Cli.FeatureSourceLoader(featureFilePaths);
var featureSources = featureSourceLoader.getSources();
return featureSources;
},
getAstFilter: function getAstFilter() {
var rules = self.getTagAstFilterRules();
rules.push(self.getSingleScenarioAstFilterRule());
var astFilter = Cucumber.Ast.Filter(rules);
return astFilter;
},
getSupportCodeLibrary: function getSupportCodeLibrary() {
var supportCodeFilePaths = argumentParser.getSupportCodeFilePaths();
var supportCodeLoader = Cucumber.Cli.SupportCodeLoader(supportCodeFilePaths);
var supportCodeLibrary = supportCodeLoader.getSupportCodeLibrary();
return supportCodeLibrary;
},
getTagAstFilterRules: function getTagAstFilterRules() {
var tagGroups = argumentParser.getTagGroups();
var rules = [];
tagGroups.forEach(function (tags) {
var rule = Cucumber.Ast.Filter.AnyOfTagsRule(tags);
rules.push(rule);
});
return rules;
},
getSingleScenarioAstFilterRule: function getSingleScenarioAstFilterRule() {
var rule = Cucumber.Ast.Filter.ScenarioAtLineRule();
return rule;
},
isHelpRequested: function isHelpRequested() {
return argumentParser.isHelpRequested();
},
isStrictRequested: function isStrictRequested() {
return argumentParser.isStrictRequested();
},
isVersionRequested: function isVersionRequested() {
return argumentParser.isVersionRequested();
},
shouldSnippetsBeInCoffeeScript: function shouldSnippetsBeInCoffeeScript() {
return argumentParser.shouldSnippetsBeInCoffeeScript();
},
shouldSnippetsBeShown: function shouldSnippetsBeShown() {
return argumentParser.shouldSnippetsBeShown();
},
shouldFilterStackTraces: function shouldFilterStackTraces() {
return argumentParser.shouldFilterStackTraces();
}
};
return self;
}
Configuration.JSON_FORMAT_NAME = 'json';
Configuration.PRETTY_FORMAT_NAME = 'pretty';
Configuration.PROGRESS_FORMAT_NAME = 'progress';
Configuration.SUMMARY_FORMAT_NAME = 'summary';
Configuration.HTML_FORMAT_NAME = 'html';
module.exports = Configuration;
var TEMPLATE = '<!doctype html>\
<html>\
<head>\
<meta charset="UTF-8">\
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">\
<title>Cucumber.js Report</title>\
<style>\
html, body {\
margin:1em;\
min-height:100%;\
font-family:helvetica, arial, freesans, clean, sans-serif;\
font-size:.95em;\
}\
\
#feature, #step-definitions, #output, #errors {\
font-family:"Bitstream Vera Sans Mono", Courier, monospace;\
font-size:1em;\
}\
\
#feature, #step-definitions, #errors {\
width:700px;\
}\
\
#feature {\
height:16em;\
}\
\
#step-definitions {\
height:28em;\
}\
\
#output {\
width: 100%;\
}\
\
#errors {\
color: #a30;\
}\
\
/* html formatter */\
\
.cucumber-report .keyword {\
font-weight: bold;\
}\
\
.cucumber-report .description {\
font-style: italic;\
margin-left: 20px;\
}\
\
.cucumber-report details > section {\
margin-left: 20px;\
}\
\
.cucumber-report ol.steps {\
list-style-type: none;\
margin-top: 0;\
margin-bottom: 0;\
}\
\
.cucumber-report .doc_string {\
margin: 0 0 0 20px;\
}\
\
.cucumber-report table {\
border-collapse: collapse;\
border: 1px;\
border-style: solid;\
}\
\
.cucumber-report td, .cucumber-report th {\
border: 1px;\
border-style: solid;\
padding-left: 4px;\
padding-right: 4px;\
}\
\
.cucumber-report table {\
margin-left: 20px;\
}\
\
.cucumber-report thead {\
background-color: #C0C0C0;\
}\
\
.cucumber-report .passed {\
background-color: #C5D88A;\
}\
\
.cucumber-report .undefined, .cucumber-report .pending {\
background-color: #EAEC2D;\
}\
\
.cucumber-report .skipped {\
background-color: #2DEAEC;\
}\
\
.cucumber-report .failed {\
background-color: #D88A8A;\
}\
\
.cucumber-report .tags {\
display: inline;\
}\
\
.cucumber-report .tag {\
margin-right: 0.25em;\
color: #246ac1;\
}\
\
.cucumber-report .comments {\
display: inline;\
}\
\
.cucumber-report .comment {\
margin 0;\
padding 0;\
}\
\
.cucumber-report .error {\
margin: .2em .75em;\
padding: .2em;\
border: 1px solid #900;\
background-color: #EDBBBB;\
}\
\
#cucumber-templates {\
display: none;\
}\
</style>\
</head>\
<body>\
<h1>Cucumber Report</h1>\
<div id="output" class="cucumber-report"></div>\
<div id="errors-container">\
<h3>Errors</h3>\
<pre id="errors"></pre>\
</div>\
</body>\
</html>';
function HtmlFormatter(options) {
if (!options) {
options = {};
}
var Cucumber = require('../../cucumber');
var self = Cucumber.Listener.Formatter(options);
var jsdom = require('jsdom').jsdom;
var document = jsdom(TEMPLATE);
var window = document.parentWindow;
$ = require('jquery')(window);
var CucumberHTML = require('cucumber-html');
var formatter = new CucumberHTML.DOMFormatter($('#output'));
var currentStep;
formatter.uri('report.feature');
self.handleBeforeFeatureEvent = function handleBeforeFeatureEvent(event, callback) {
var feature = event.getPayloadItem('feature');
formatter.feature({
keyword : feature.getKeyword(),
name : feature.getName(),
line : feature.getLine(),
description : feature.getDescription()
});
callback();
};
self.handleBeforeScenarioEvent = function handleBeforeScenarioEvent(event, callback) {
var scenario = event.getPayloadItem('scenario');
formatter.scenario({
keyword : scenario.getKeyword(),
name : scenario.getName(),
line : scenario.getLine(),
description : scenario.getDescription()
});
callback();
};
self.handleAnyStep = function handleAnyStep(step) {
formatter.step({
keyword: step.getKeyword(),
name : step.getName(),
line : step.getLine(),
});
currentStep = step;
};
self.handleBeforeStepEvent = function handleBeforeStepEvent(event, callback) {
var step = event.getPayloadItem('step');
self.handleAnyStep(step);
callback();
};
self.handleStepResultEvent = function handleStepResultEvent(event, callback) {
var result;
var stepResult = event.getPayloadItem('stepResult');
if (stepResult.isSuccessful()) {
result = {status: 'passed'};
} else if (stepResult.isPending()) {
result = {status: 'pending'};
} else if (stepResult.isUndefined() || stepResult.isSkipped()) {
result = {status:'skipped'};
} else {
var error = stepResult.getFailureException();
var errorMessage = error.stack || error;
result = {status: 'failed', error_message: errorMessage};
}
formatter.match({uri:'report.feature', step: {line: currentStep.getLine()}});
formatter.result(result);
callback();
};
self.handleAfterFeaturesEvent = function handleAfterFeaturesEvent(event, callback) {
self.log(window.document.documentElement.outerHTML);
callback();
};
return self;
}
module.exports = HtmlFormatter;
function Listener() {
var self = {
hear: function hear(event, callback) {
if (self.hasHandlerForEvent(event)) {
var handler = self.getHandlerForEvent(event);
handler(event, callback);
} else {
callback();
}
},
hasHandlerForEvent: function hasHandlerForEvent(event) {
var handlerName = self.buildHandlerNameForEvent(event);
return self[handlerName] !== undefined;
},
buildHandlerNameForEvent: function buildHandlerNameForEvent(event) {
return self.buildHandlerName(event.getName());
},
getHandlerForEvent: function getHandlerForEvent(event) {
var eventHandlerName = self.buildHandlerNameForEvent(event);
return self[eventHandlerName];
},
buildHandlerName: function buildHandler(shortName) {
return Listener.EVENT_HANDLER_NAME_PREFIX + shortName + Listener.EVENT_HANDLER_NAME_SUFFIX;
},
setHandlerForEvent: function setHandlerForEvent(shortname, handler) {
var eventName = self.buildHandlerName(shortname);
self[eventName] = handler;
}
};
return self;
}
Listener.EVENT_HANDLER_NAME_PREFIX = 'handle';
Listener.EVENT_HANDLER_NAME_SUFFIX = 'Event';
Listener.Events = require('./listener/events');
Listener.Formatter = require('./listener/formatter');
Listener.PrettyFormatter = require('./listener/pretty_formatter');
Listener.ProgressFormatter = require('./listener/progress_formatter');
Listener.JsonFormatter = require('./listener/json_formatter');
Listener.StatsJournal = require('./listener/stats_journal');
Listener.SummaryFormatter = require('./listener/summary_formatter');
Listener.HtmlFormatter = require('./listener/html_formatter');
module.exports = Listener;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment