yachr
Version:
Yet another cucumber html reporter
196 lines • 8.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Reporter = void 0;
const fs = require("fs");
const Handlebars = require("handlebars");
const marked = require("marked");
const resultStatus_1 = require("./models/reporter/resultStatus");
const reportAggregator_1 = require("./reportAggregator");
/**
* The main YACHR Cucumber HTML Report generator.
* Provides an API to read in a Cucumber Test Report,
* and generate a static HTML page which summarises the report
* into a dashboard
*/
class Reporter {
/**
* Generates the HTML Report summary for the Cucumber Test Report.
* @param options Options to configure how the reporter will generate the HTML report
*/
generate(options) {
options = this.populateDefaultOptionsIfMissing(options);
const rawResults = this.parseJsonFile(options.jsonFile);
// if a filter has been passed in, filter out the results
const results = this.filterResults(rawResults, options);
const aggregator = new reportAggregator_1.ReportAggregator();
const data = {
cucumberReportSummary: aggregator.getSummaryForSuite(results),
cucumberResult: results,
generateTime: (new Date()).toLocaleString()
};
if (!options.htmlTemplate) {
throw new Error('htmlTemplate not supplied in ReportOptions');
}
if (!options.featureTemplate) {
throw new Error('featureTemplate not supplied in ReportOptions');
}
if (!options.scenarioTemplate) {
throw new Error('scenarioTemplate not supplied in ReportOptions');
}
let reportTemplate;
let featureTemplate;
let scenarioTemplate;
try {
reportTemplate = fs.readFileSync(options.htmlTemplate, 'utf8');
featureTemplate = fs.readFileSync(options.featureTemplate, 'utf8');
scenarioTemplate = fs.readFileSync(options.scenarioTemplate, 'utf8');
}
catch (err) {
throw new Error(`Error reading htmlTemplate: ${err}`);
}
const template = Handlebars.compile(reportTemplate);
// Gross work around because the template engine seems to reject
// the work undefined as a property.
Handlebars.registerHelper('countOf', (obj, property) => (obj)[property]);
Handlebars.registerPartial({
feature: Handlebars.compile(featureTemplate),
});
Handlebars.registerPartial({
scenario: Handlebars.compile(scenarioTemplate),
});
Handlebars.registerHelper('getFeatureCss', (featureSummary) => this.getFeatureCss(featureSummary));
Handlebars.registerHelper('getScenarioCss', (scenarioSummary) => this.getScenarioCss(scenarioSummary));
Handlebars.registerHelper('markdown2Html', (markdown) => marked.parse(markdown && markdown.trim() || ''));
Handlebars.registerHelper('getStepCss', (step) => {
switch (step.result.status) {
case resultStatus_1.ResultStatus.failed:
return 'failing-step';
case resultStatus_1.ResultStatus.ambiguous:
return 'ambiguous-step';
case resultStatus_1.ResultStatus.undefined:
return 'undefined-step';
// Both pending and skipped will be styled the same
case resultStatus_1.ResultStatus.pending:
case resultStatus_1.ResultStatus.skipped:
return 'pending-step';
case resultStatus_1.ResultStatus.passed:
return 'passing-step';
default:
return '';
}
});
const htmlReport = template(data);
try {
fs.writeFileSync(options.output, htmlReport, 'utf8');
}
catch (err) {
console.error(`Error writing report to file: ${err}`);
}
}
/**
* Parses a JSON file (at the given file path) into the data model for
* the Cucumber Report. This report can then be used with strong typing
* when accessing components of the report
* @param resultsFile The path to the Cucumber Test Results file
*/
parseJsonFile(resultsFile) {
try {
const results = fs.readFileSync(resultsFile, 'utf8');
return this.parseJsonString(results);
}
catch (err) {
console.error('Error reading file: ' + resultsFile);
throw (err);
}
}
/**
* Filters the features and scenario's based on tags
*/
filterResults(featureSuiteOrig, options) {
// Don't modify the original suite
const featureSuite = JSON.parse(JSON.stringify(featureSuiteOrig));
if (options.tags && options.tags.length) {
const tags = (options.tags || '').split(',').map(t => t.trim());
const includeTags = tags.filter(t => t.startsWith('@'));
const excludeTags = tags.filter(t => t.startsWith('~')).map(t => t.substring(1)); // Drop the tilde
let filteredFeatures = featureSuite.features.filter(f => {
const x = (!includeTags.length || f.tags.some(t => includeTags.includes(t.name)));
const y = (!excludeTags.length || !f.tags.some(t => excludeTags.includes(t.name)));
return x && y;
});
filteredFeatures.forEach(f => f.elements = f.elements.filter(el => {
const x = (!includeTags.length || el.tags.some(t => includeTags.includes(t.name)));
const y = (!excludeTags.length || !el.tags.some(t => excludeTags.includes(t.name)));
return x && y;
}));
filteredFeatures = filteredFeatures.filter(f => f.elements.length);
return { features: filteredFeatures };
}
return featureSuite;
}
/**
* Parses a JSON String and returns a strongly typed data model
* reflecting the Cucumber Test Report data structure
* @param results An array of Cucumber Features from the Test Report
*/
parseJsonString(results) {
const features = JSON.parse(results);
return { features };
}
/**
* Used by generate to add in any default options that need to overwrite empty parameters
* @param options The options as passed in by the user
*/
populateDefaultOptionsIfMissing(options) {
const defaultOptions = {
featureTemplate: __dirname + '/templates/feature.html',
htmlTemplate: __dirname + '/templates/standard.html',
scenarioTemplate: __dirname + '/templates/scenario.html'
};
return Object.assign(Object.assign({}, defaultOptions), options);
}
/**
* Generates the cess for the feature block of html
*/
getFeatureCss(featureSummary) {
if (featureSummary.hasFailed) {
return 'failing-feature';
}
if (featureSummary.hasAmbiguous) {
return 'ambiguous-feature';
}
if (featureSummary.hasUndefined) {
return 'undefined-feature';
}
if (featureSummary.hasPending) {
return 'pending-feature';
}
if (featureSummary.isPassed) {
return 'passing-feature';
}
return '';
}
/**
* Returns the css for the scenario block
*/
getScenarioCss(scenarioSummary) {
if (scenarioSummary.hasFailed) {
return 'failing-scenario';
}
if (scenarioSummary.hasAmbiguous) {
return 'ambiguous-scenario';
}
if (scenarioSummary.hasUndefined) {
return 'undefined-scenario';
}
if (scenarioSummary.hasPending) {
return 'pending-scenario';
}
if (scenarioSummary.isPassed) {
return 'passing-scenario';
}
return '';
}
}
exports.Reporter = Reporter;
//# sourceMappingURL=reporter.js.map