multiple-cucumber-html-reporter
Advanced tools
Comparing version 1.21.5 to 1.21.6
@@ -20,16 +20,21 @@ 'use strict'; | ||
let FEATURES_OVERVIEW_TEMPLATE = 'components/features-overview.tmpl'; | ||
const FEATURES_OVERVIEW_CUSTOM_METADATA_TEMPLATE = 'components/features-overview-custom-metadata.tmpl'; | ||
const FEATURES_OVERVIEW_CHART_TEMPLATE = 'components/features-overview.chart.tmpl'; | ||
const SCENARIOS_OVERVIEW_CHART_TEMPLATE = 'components/scenarios-overview.chart.tmpl'; | ||
const FEATURES_OVERVIEW_CUSTOM_METADATA_TEMPLATE = | ||
'components/features-overview-custom-metadata.tmpl'; | ||
const FEATURES_OVERVIEW_CHART_TEMPLATE = | ||
'components/features-overview.chart.tmpl'; | ||
const SCENARIOS_OVERVIEW_CHART_TEMPLATE = | ||
'components/scenarios-overview.chart.tmpl'; | ||
const FEATURE_OVERVIEW_INDEX_TEMPLATE = 'feature-overview.index.tmpl'; | ||
let FEATURE_METADATA_OVERVIEW_TEMPLATE = 'components/feature-metadata-overview.tmpl'; | ||
const FEATURE_CUSTOM_METADATA_OVERVIEW_TEMPLATE = 'components/feature-custom-metadata-overview.tmpl'; | ||
let FEATURE_METADATA_OVERVIEW_TEMPLATE = | ||
'components/feature-metadata-overview.tmpl'; | ||
const FEATURE_CUSTOM_METADATA_OVERVIEW_TEMPLATE = | ||
'components/feature-custom-metadata-overview.tmpl'; | ||
const SCENARIOS_TEMPLATE = 'components/scenarios.tmpl'; | ||
const RESULT_STATUS = { | ||
passed: 'passed', | ||
failed: 'failed', | ||
skipped: 'skipped', | ||
pending: 'pending', | ||
notDefined: 'undefined', | ||
ambiguous: 'ambiguous' | ||
passed: 'passed', | ||
failed: 'failed', | ||
skipped: 'skipped', | ||
pending: 'pending', | ||
notDefined: 'undefined', | ||
ambiguous: 'ambiguous', | ||
}; | ||
@@ -39,521 +44,647 @@ const DEFAULT_REPORT_NAME = 'Multiple Cucumber HTML Reporter'; | ||
function generateReport(options) { | ||
if (!options) { | ||
throw new Error('Options need to be provided.'); | ||
} | ||
if (!options) { | ||
throw new Error('Options need to be provided.'); | ||
} | ||
if (!options.jsonDir) { | ||
throw new Error('A path which holds the JSON files should be provided.'); | ||
} | ||
if (!options.jsonDir) { | ||
throw new Error('A path which holds the JSON files should be provided.'); | ||
} | ||
if (!options.reportPath) { | ||
throw new Error('An output path for the reports should be defined, no path was provided.'); | ||
} | ||
if (!options.reportPath) { | ||
throw new Error( | ||
'An output path for the reports should be defined, no path was provided.' | ||
); | ||
} | ||
const customMetadata = !!options.customMetadata; | ||
const customData = options.customData || null; | ||
const plainDescription = !!options.plainDescription; | ||
const style = options.overrideStyle || REPORT_STYLESHEET; | ||
const customStyle = options.customStyle; | ||
const disableLog = !!options.disableLog; | ||
const openReportInBrowser = !!options.openReportInBrowser; | ||
const reportName = options.reportName || DEFAULT_REPORT_NAME; | ||
const reportPath = path.resolve(process.cwd(), options.reportPath); | ||
const saveCollectedJSON = !!options.saveCollectedJSON; | ||
const displayDuration = !!options.displayDuration; | ||
const displayReportTime = !!options.displayReportTime; | ||
const durationInMS = !!options.durationInMS; | ||
const hideMetadata = !!options.hideMetadata; | ||
const pageTitle = options.pageTitle || 'Multiple Cucumber HTML Reporter'; | ||
const pageFooter = options.pageFooter || null; | ||
const useCDN = !!options.useCDN; | ||
const staticFilePath = !!options.staticFilePath; | ||
const customMetadata = !!options.customMetadata; | ||
const customData = options.customData || null; | ||
const plainDescription = !!options.plainDescription; | ||
const style = options.overrideStyle || REPORT_STYLESHEET; | ||
const customStyle = options.customStyle; | ||
const disableLog = !!options.disableLog; | ||
const openReportInBrowser = !!options.openReportInBrowser; | ||
const reportName = options.reportName || DEFAULT_REPORT_NAME; | ||
const reportPath = path.resolve(process.cwd(), options.reportPath); | ||
const saveCollectedJSON = !!options.saveCollectedJSON; | ||
const displayDuration = !!options.displayDuration; | ||
const displayReportTime = !!options.displayReportTime; | ||
const durationInMS = !!options.durationInMS; | ||
const hideMetadata = !!options.hideMetadata; | ||
const pageTitle = options.pageTitle || 'Multiple Cucumber HTML Reporter'; | ||
const pageFooter = options.pageFooter || null; | ||
const useCDN = !!options.useCDN; | ||
const staticFilePath = !!options.staticFilePath; | ||
fs.ensureDirSync(reportPath); | ||
fs.ensureDirSync(path.resolve(reportPath, FEATURE_FOLDER)); | ||
fs.ensureDirSync(reportPath); | ||
fs.ensureDirSync(path.resolve(reportPath, FEATURE_FOLDER)); | ||
const allFeatures = collectJSONS(options); | ||
const allFeatures = collectJSONS(options); | ||
let suite = { | ||
app: 0, | ||
customMetadata: customMetadata, | ||
customData: customData, | ||
style: style, | ||
customStyle: customStyle, | ||
useCDN: useCDN, | ||
hideMetadata: hideMetadata, | ||
displayReportTime: displayReportTime, | ||
displayDuration: displayDuration, | ||
browser: 0, | ||
name: '', | ||
version: 'version', | ||
time: new Date(), | ||
features: allFeatures, | ||
featureCount: { | ||
ambiguous: 0, | ||
failed: 0, | ||
passed: 0, | ||
notDefined: 0, | ||
pending: 0, | ||
skipped: 0, | ||
total: 0, | ||
ambiguousPercentage: 0, | ||
failedPercentage: 0, | ||
notDefinedPercentage: 0, | ||
pendingPercentage: 0, | ||
skippedPercentage: 0, | ||
passedPercentage: 0 | ||
}, | ||
reportName: reportName, | ||
scenarios: { | ||
failed: 0, | ||
ambiguous: 0, | ||
notDefined: 0, | ||
pending: 0, | ||
skipped: 0, | ||
passed: 0, | ||
total: 0 | ||
}, | ||
totalTime: 0 | ||
}; | ||
let suite = { | ||
app: 0, | ||
customMetadata: customMetadata, | ||
customData: customData, | ||
style: style, | ||
customStyle: customStyle, | ||
useCDN: useCDN, | ||
hideMetadata: hideMetadata, | ||
displayReportTime: displayReportTime, | ||
displayDuration: displayDuration, | ||
browser: 0, | ||
name: '', | ||
version: 'version', | ||
time: new Date(), | ||
features: allFeatures, | ||
featureCount: { | ||
ambiguous: 0, | ||
failed: 0, | ||
passed: 0, | ||
notDefined: 0, | ||
pending: 0, | ||
skipped: 0, | ||
total: 0, | ||
ambiguousPercentage: 0, | ||
failedPercentage: 0, | ||
notDefinedPercentage: 0, | ||
pendingPercentage: 0, | ||
skippedPercentage: 0, | ||
passedPercentage: 0, | ||
}, | ||
reportName: reportName, | ||
scenarios: { | ||
failed: 0, | ||
ambiguous: 0, | ||
notDefined: 0, | ||
pending: 0, | ||
skipped: 0, | ||
passed: 0, | ||
total: 0, | ||
}, | ||
totalTime: 0, | ||
}; | ||
_parseFeatures(suite); | ||
_parseFeatures(suite); | ||
// Percentages | ||
suite.featureCount.ambiguousPercentage = _calculatePercentage(suite.featureCount.ambiguous, suite.featureCount.total); | ||
suite.featureCount.failedPercentage = _calculatePercentage(suite.featureCount.failed, suite.featureCount.total); | ||
suite.featureCount.notDefinedPercentage = _calculatePercentage(suite.featureCount.notDefined, suite.featureCount.total); | ||
suite.featureCount.pendingPercentage = _calculatePercentage(suite.featureCount.pending, suite.featureCount.total); | ||
suite.featureCount.skippedPercentage = _calculatePercentage(suite.featureCount.skipped, suite.featureCount.total); | ||
suite.featureCount.passedPercentage = _calculatePercentage(suite.featureCount.passed, suite.featureCount.total); | ||
// Percentages | ||
suite.featureCount.ambiguousPercentage = _calculatePercentage( | ||
suite.featureCount.ambiguous, | ||
suite.featureCount.total | ||
); | ||
suite.featureCount.failedPercentage = _calculatePercentage( | ||
suite.featureCount.failed, | ||
suite.featureCount.total | ||
); | ||
suite.featureCount.notDefinedPercentage = _calculatePercentage( | ||
suite.featureCount.notDefined, | ||
suite.featureCount.total | ||
); | ||
suite.featureCount.pendingPercentage = _calculatePercentage( | ||
suite.featureCount.pending, | ||
suite.featureCount.total | ||
); | ||
suite.featureCount.skippedPercentage = _calculatePercentage( | ||
suite.featureCount.skipped, | ||
suite.featureCount.total | ||
); | ||
suite.featureCount.passedPercentage = _calculatePercentage( | ||
suite.featureCount.passed, | ||
suite.featureCount.total | ||
); | ||
/** | ||
* Calculate and return the percentage | ||
* @param {number} amount | ||
* @param {number} total | ||
* @return {string} percentage | ||
* @private | ||
*/ | ||
function _calculatePercentage(amount, total) { | ||
return ((amount / total) * 100).toFixed(2); | ||
} | ||
/** | ||
* Calculate and return the percentage | ||
* @param {number} amount | ||
* @param {number} total | ||
* @return {string} percentage | ||
* @private | ||
*/ | ||
function _calculatePercentage(amount, total) { | ||
return ((amount / total) * 100).toFixed(2); | ||
} | ||
/* istanbul ignore else */ | ||
if (saveCollectedJSON) { | ||
jsonFile.writeFileSync(path.resolve(reportPath, 'enriched-output.json'), suite, { spaces: 2 }); | ||
} | ||
/* istanbul ignore else */ | ||
if (saveCollectedJSON) { | ||
jsonFile.writeFileSync( | ||
path.resolve(reportPath, 'enriched-output.json'), | ||
suite, | ||
{ spaces: 2 } | ||
); | ||
} | ||
_createFeaturesOverviewIndexPage(suite); | ||
_createFeatureIndexPages(suite); | ||
_createFeaturesOverviewIndexPage(suite); | ||
_createFeatureIndexPages(suite); | ||
/* istanbul ignore else */ | ||
if (!disableLog) { | ||
console.log(chalk.blue(`\n | ||
/* istanbul ignore else */ | ||
if (!disableLog) { | ||
console.log( | ||
chalk.blue(`\n | ||
===================================================================================== | ||
Multiple Cucumber HTML report generated in: | ||
${ path.join(reportPath, INDEX_HTML) } | ||
=====================================================================================\n`)); | ||
} | ||
${path.join(reportPath, INDEX_HTML)} | ||
=====================================================================================\n`) | ||
); | ||
} | ||
/* istanbul ignore if */ | ||
if (openReportInBrowser) { | ||
open(path.join(reportPath, INDEX_HTML)); | ||
} | ||
/* istanbul ignore if */ | ||
if (openReportInBrowser) { | ||
open(path.join(reportPath, INDEX_HTML)); | ||
} | ||
function _parseFeatures(suite) { | ||
suite.features.forEach(feature => { | ||
feature.scenarios = { | ||
passed: 0, | ||
failed: 0, | ||
notDefined: 0, | ||
skipped: 0, | ||
pending: 0, | ||
ambiguous: 0, | ||
passedPercentage: 0, | ||
failedPercentage: 0, | ||
notDefinedPercentage: 0, | ||
skippedPercentage: 0, | ||
pendingPercentage: 0, | ||
ambiguousPercentage: 0, | ||
total: 0 | ||
}; | ||
feature.duration = 0; | ||
feature.time = '00:00:00.000'; | ||
feature.isFailed = false; | ||
feature.isAmbiguous = false; | ||
feature.isSkipped = false; | ||
feature.isNotdefined = false; | ||
feature.isPending = false; | ||
suite.featureCount.total++; | ||
const idPrefix = staticFilePath ? '' : `${ uuid() }.` ; | ||
feature.id = `${ idPrefix }${ feature.id }`.replace(/[^a-zA-Z0-9-_]/g, '-'); | ||
feature.app = 0; | ||
feature.browser = 0; | ||
function _parseFeatures(suite) { | ||
suite.features.forEach((feature) => { | ||
feature.scenarios = { | ||
passed: 0, | ||
failed: 0, | ||
notDefined: 0, | ||
skipped: 0, | ||
pending: 0, | ||
ambiguous: 0, | ||
passedPercentage: 0, | ||
failedPercentage: 0, | ||
notDefinedPercentage: 0, | ||
skippedPercentage: 0, | ||
pendingPercentage: 0, | ||
ambiguousPercentage: 0, | ||
total: 0, | ||
}; | ||
feature.duration = 0; | ||
feature.time = '00:00:00.000'; | ||
feature.isFailed = false; | ||
feature.isAmbiguous = false; | ||
feature.isSkipped = false; | ||
feature.isNotdefined = false; | ||
feature.isPending = false; | ||
suite.featureCount.total++; | ||
const idPrefix = staticFilePath ? '' : `${uuid()}.`; | ||
feature.id = `${idPrefix}${feature.id}`.replace(/[^a-zA-Z0-9-_]/g, '-'); | ||
feature.app = 0; | ||
feature.browser = 0; | ||
if (!feature.elements) { | ||
return; | ||
} | ||
if (!feature.elements) { | ||
return; | ||
} | ||
feature = _parseScenarios(feature, suite); | ||
feature = _parseScenarios(feature, suite); | ||
if (feature.isFailed) { | ||
suite.featureCount.failed++; | ||
feature.failed++; | ||
} else if (feature.isAmbiguous) { | ||
suite.featureCount.ambiguous++; | ||
feature.ambiguous++; | ||
} else if (feature.isNotdefined) { | ||
feature.notDefined++; | ||
suite.featureCount.notDefined++; | ||
} else if (feature.isPending) { | ||
feature.pending++; | ||
suite.featureCount.pending++; | ||
} else if (feature.isSkipped) { | ||
feature.skipped++; | ||
suite.featureCount.skipped++; | ||
} else { | ||
feature.passed++; | ||
suite.featureCount.passed++; | ||
} | ||
if (feature.isFailed) { | ||
suite.featureCount.failed++; | ||
feature.failed++; | ||
} else if (feature.isAmbiguous) { | ||
suite.featureCount.ambiguous++; | ||
feature.ambiguous++; | ||
} else if (feature.isNotdefined) { | ||
feature.notDefined++; | ||
suite.featureCount.notDefined++; | ||
} else if (feature.isPending) { | ||
feature.pending++; | ||
suite.featureCount.pending++; | ||
} else if (feature.isSkipped) { | ||
feature.skipped++; | ||
suite.featureCount.skipped++; | ||
} else { | ||
feature.passed++; | ||
suite.featureCount.passed++; | ||
} | ||
if (feature.duration) { | ||
feature.totalTime += feature.duration | ||
feature.time = formatDuration(feature.duration) | ||
} | ||
if (feature.duration) { | ||
feature.totalTime += feature.duration; | ||
feature.time = formatDuration(feature.duration); | ||
} | ||
// Check if browser / app is used | ||
suite.app = feature.metadata.app ? suite.app + 1 : suite.app; | ||
suite.browser = feature.metadata.browser ? suite.browser + 1 : suite.browser; | ||
// Check if browser / app is used | ||
suite.app = feature.metadata.app ? suite.app + 1 : suite.app; | ||
suite.browser = feature.metadata.browser | ||
? suite.browser + 1 | ||
: suite.browser; | ||
// Percentages | ||
feature.scenarios.ambiguousPercentage = _calculatePercentage(feature.scenarios.ambiguous, feature.scenarios.total); | ||
feature.scenarios.failedPercentage = _calculatePercentage(feature.scenarios.failed, feature.scenarios.total); | ||
feature.scenarios.notDefinedPercentage = _calculatePercentage(feature.scenarios.notDefined, feature.scenarios.total); | ||
feature.scenarios.passedPercentage = _calculatePercentage(feature.scenarios.passed, feature.scenarios.total); | ||
feature.scenarios.pendingPercentage = _calculatePercentage(feature.scenarios.pending, feature.scenarios.total); | ||
feature.scenarios.skippedPercentage = _calculatePercentage(feature.scenarios.skipped, feature.scenarios.total); | ||
suite.scenarios.ambiguousPercentage = _calculatePercentage(suite.scenarios.ambiguous, suite.scenarios.total); | ||
suite.scenarios.failedPercentage = _calculatePercentage(suite.scenarios.failed, suite.scenarios.total); | ||
suite.scenarios.notDefinedPercentage = _calculatePercentage(suite.scenarios.notDefined, suite.scenarios.total); | ||
suite.scenarios.passedPercentage = _calculatePercentage(suite.scenarios.passed, suite.scenarios.total); | ||
suite.scenarios.pendingPercentage = _calculatePercentage(suite.scenarios.pending, suite.scenarios.total); | ||
suite.scenarios.skippedPercentage = _calculatePercentage(suite.scenarios.skipped, suite.scenarios.total); | ||
}); | ||
} | ||
// Percentages | ||
feature.scenarios.ambiguousPercentage = _calculatePercentage( | ||
feature.scenarios.ambiguous, | ||
feature.scenarios.total | ||
); | ||
feature.scenarios.failedPercentage = _calculatePercentage( | ||
feature.scenarios.failed, | ||
feature.scenarios.total | ||
); | ||
feature.scenarios.notDefinedPercentage = _calculatePercentage( | ||
feature.scenarios.notDefined, | ||
feature.scenarios.total | ||
); | ||
feature.scenarios.passedPercentage = _calculatePercentage( | ||
feature.scenarios.passed, | ||
feature.scenarios.total | ||
); | ||
feature.scenarios.pendingPercentage = _calculatePercentage( | ||
feature.scenarios.pending, | ||
feature.scenarios.total | ||
); | ||
feature.scenarios.skippedPercentage = _calculatePercentage( | ||
feature.scenarios.skipped, | ||
feature.scenarios.total | ||
); | ||
suite.scenarios.ambiguousPercentage = _calculatePercentage( | ||
suite.scenarios.ambiguous, | ||
suite.scenarios.total | ||
); | ||
suite.scenarios.failedPercentage = _calculatePercentage( | ||
suite.scenarios.failed, | ||
suite.scenarios.total | ||
); | ||
suite.scenarios.notDefinedPercentage = _calculatePercentage( | ||
suite.scenarios.notDefined, | ||
suite.scenarios.total | ||
); | ||
suite.scenarios.passedPercentage = _calculatePercentage( | ||
suite.scenarios.passed, | ||
suite.scenarios.total | ||
); | ||
suite.scenarios.pendingPercentage = _calculatePercentage( | ||
suite.scenarios.pending, | ||
suite.scenarios.total | ||
); | ||
suite.scenarios.skippedPercentage = _calculatePercentage( | ||
suite.scenarios.skipped, | ||
suite.scenarios.total | ||
); | ||
}); | ||
} | ||
/** | ||
* Parse each scenario within a feature | ||
* @param {object} feature a feature with all the scenarios in it | ||
* @return {object} return the parsed feature | ||
* @private | ||
*/ | ||
function _parseScenarios(feature) { | ||
feature.elements.forEach(scenario => { | ||
scenario.passed = 0; | ||
scenario.failed = 0; | ||
scenario.notDefined = 0; | ||
scenario.skipped = 0; | ||
scenario.pending = 0; | ||
scenario.ambiguous = 0; | ||
scenario.duration = 0; | ||
scenario.time = '00:00:00.000'; | ||
/** | ||
* Parse each scenario within a feature | ||
* @param {object} feature a feature with all the scenarios in it | ||
* @return {object} return the parsed feature | ||
* @private | ||
*/ | ||
function _parseScenarios(feature) { | ||
feature.elements.forEach((scenario) => { | ||
scenario.passed = 0; | ||
scenario.failed = 0; | ||
scenario.notDefined = 0; | ||
scenario.skipped = 0; | ||
scenario.pending = 0; | ||
scenario.ambiguous = 0; | ||
scenario.duration = 0; | ||
scenario.time = '00:00:00.000'; | ||
scenario = _parseSteps(scenario); | ||
scenario = _parseSteps(scenario); | ||
if (scenario.duration > 0) { | ||
feature.duration += scenario.duration; | ||
scenario.time = formatDuration(scenario.duration) | ||
} | ||
if (scenario.duration > 0) { | ||
feature.duration += scenario.duration; | ||
scenario.time = formatDuration(scenario.duration); | ||
} | ||
if (scenario.hasOwnProperty('description') && scenario.description) { | ||
scenario.description = scenario.description.replace(new RegExp('\r?\n', 'g'), '<br />'); | ||
} | ||
if (scenario.hasOwnProperty('description') && scenario.description) { | ||
scenario.description = scenario.description.replace( | ||
new RegExp('\r?\n', 'g'), | ||
'<br />' | ||
); | ||
} | ||
if (scenario.type === "background") { | ||
return | ||
} | ||
if (scenario.type === 'background') { | ||
return; | ||
} | ||
if (scenario.failed > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.failed++; | ||
feature.scenarios.total++; | ||
feature.isFailed = true; | ||
return feature.scenarios.failed++; | ||
} | ||
if (scenario.failed > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.failed++; | ||
feature.scenarios.total++; | ||
feature.isFailed = true; | ||
return feature.scenarios.failed++; | ||
} | ||
if (scenario.ambiguous > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.ambiguous++; | ||
feature.scenarios.total++; | ||
feature.isAmbiguous = true; | ||
return feature.scenarios.ambiguous++; | ||
} | ||
if (scenario.ambiguous > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.ambiguous++; | ||
feature.scenarios.total++; | ||
feature.isAmbiguous = true; | ||
return feature.scenarios.ambiguous++; | ||
} | ||
if (scenario.notDefined > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.notDefined++; | ||
feature.scenarios.total++; | ||
feature.isNotdefined = true; | ||
return feature.scenarios.notDefined++; | ||
} | ||
if (scenario.notDefined > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.notDefined++; | ||
feature.scenarios.total++; | ||
feature.isNotdefined = true; | ||
return feature.scenarios.notDefined++; | ||
} | ||
if (scenario.pending > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.pending++; | ||
feature.scenarios.total++; | ||
feature.isPending = true; | ||
return feature.scenarios.pending++; | ||
} | ||
if (scenario.pending > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.pending++; | ||
feature.scenarios.total++; | ||
feature.isPending = true; | ||
return feature.scenarios.pending++; | ||
} | ||
if (scenario.skipped > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.skipped++; | ||
feature.scenarios.total++; | ||
return feature.scenarios.skipped++; | ||
} | ||
if (scenario.skipped > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.skipped++; | ||
feature.scenarios.total++; | ||
return feature.scenarios.skipped++; | ||
} | ||
/* istanbul ignore else */ | ||
if (scenario.passed > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.passed++; | ||
feature.scenarios.total++; | ||
return feature.scenarios.passed++; | ||
} | ||
}); | ||
/* istanbul ignore else */ | ||
if (scenario.passed > 0) { | ||
suite.scenarios.total++; | ||
suite.scenarios.passed++; | ||
feature.scenarios.total++; | ||
return feature.scenarios.passed++; | ||
} | ||
}); | ||
feature.isSkipped = feature.scenarios.total === feature.scenarios.skipped; | ||
feature.isSkipped = feature.scenarios.total === feature.scenarios.skipped; | ||
return feature; | ||
} | ||
return feature; | ||
} | ||
/** | ||
* Parse all the scenario steps and enrich them with the correct data | ||
* @param {object} scenario Preparsed scenario | ||
* @return {object} A parsed scenario | ||
* @private | ||
*/ | ||
function _parseSteps(scenario) { | ||
scenario.steps.forEach(step => { | ||
if (step.embeddings !== undefined) { | ||
step.attachments = []; | ||
step.embeddings.forEach((embedding, embeddingIndex) => { | ||
/* istanbul ignore else */ | ||
if (embedding.mime_type === 'application/json' || embedding.media && embedding.media.type === 'application/json') { | ||
step.json = (step.json ? step.json : []).concat([typeof embedding.data === 'string' ? JSON.parse(embedding.data) : embedding.data]); | ||
} else if (embedding.mime_type === 'text/html' || (embedding.media && embedding.media.type === 'text/html')) { | ||
step.html = (step.html ? step.html : []).concat([embedding.data]); | ||
} else if (embedding.mime_type === 'text/plain' || (embedding.media && embedding.media.type === 'text/plain')) { | ||
step.text = (step.text ? step.text : []).concat([_escapeHtml(embedding.data)]); | ||
} else if (embedding.mime_type === 'image/png' || (embedding.media && embedding.media.type === 'image/png')) { | ||
step.image = (step.image ? step.image : []).concat([ 'data:image/png;base64,' + embedding.data ]); | ||
step.embeddings[ embeddingIndex ] = {}; | ||
} else { | ||
let embeddingType = 'text/plain'; | ||
if (embedding.mime_type) { | ||
embeddingType = embedding.mime_type; | ||
} else if (embedding.media && embedding.media.type) { | ||
embeddingType = embedding.media.type; | ||
} | ||
step.attachments.push({ | ||
data: 'data:' + embeddingType + ';base64,' + embedding.data, | ||
type: embeddingType | ||
}); | ||
step.embeddings[ embeddingIndex ] = {}; | ||
} | ||
}); | ||
} | ||
/** | ||
* Parse all the scenario steps and enrich them with the correct data | ||
* @param {object} scenario Preparsed scenario | ||
* @return {object} A parsed scenario | ||
* @private | ||
*/ | ||
function _parseSteps(scenario) { | ||
scenario.steps.forEach((step) => { | ||
if (step.embeddings !== undefined) { | ||
step.attachments = []; | ||
step.embeddings.forEach((embedding, embeddingIndex) => { | ||
/* istanbul ignore else */ | ||
if ( | ||
embedding.mime_type === 'application/json' || | ||
(embedding.media && embedding.media.type === 'application/json') | ||
) { | ||
step.json = (step.json ? step.json : []).concat([ | ||
typeof embedding.data === 'string' | ||
? JSON.parse(embedding.data) | ||
: embedding.data, | ||
]); | ||
} else if ( | ||
embedding.mime_type === 'text/html' || | ||
(embedding.media && embedding.media.type === 'text/html') | ||
) { | ||
step.html = (step.html ? step.html : []).concat([embedding.data]); | ||
} else if ( | ||
embedding.mime_type === 'text/plain' || | ||
(embedding.media && embedding.media.type === 'text/plain') | ||
) { | ||
step.text = (step.text ? step.text : []).concat([ | ||
_escapeHtml(embedding.data), | ||
]); | ||
} else if ( | ||
embedding.mime_type === 'image/png' || | ||
(embedding.media && embedding.media.type === 'image/png') | ||
) { | ||
step.image = (step.image ? step.image : []).concat([ | ||
'data:image/png;base64,' + embedding.data, | ||
]); | ||
step.embeddings[embeddingIndex] = {}; | ||
} else { | ||
let embeddingType = 'text/plain'; | ||
if (embedding.mime_type) { | ||
embeddingType = embedding.mime_type; | ||
} else if (embedding.media && embedding.media.type) { | ||
embeddingType = embedding.media.type; | ||
} | ||
step.attachments.push({ | ||
data: 'data:' + embeddingType + ';base64,' + embedding.data, | ||
type: embeddingType, | ||
}); | ||
step.embeddings[embeddingIndex] = {}; | ||
} | ||
}); | ||
} | ||
if (step.doc_string !== undefined) { | ||
step.id = `${uuid()}.${scenario.id}.${step.name}`.replace(/[^a-zA-Z0-9-_]/g, '-'); | ||
step.restWireData = _escapeHtml(step.doc_string.value).replace(new RegExp('\r?\n', 'g'), '<br />'); | ||
} | ||
if (step.doc_string !== undefined) { | ||
step.id = `${uuid()}.${scenario.id}.${step.name}`.replace( | ||
/[^a-zA-Z0-9-_]/g, | ||
'-' | ||
); | ||
step.restWireData = _escapeHtml(step.doc_string.value).replace( | ||
new RegExp('\r?\n', 'g'), | ||
'<br />' | ||
); | ||
} | ||
if (!step.result | ||
// Don't log steps that don't have a text/hidden/images/attachments unless they are failed. | ||
// This is for the hooks | ||
|| (step.hidden && !step.text && !step.image && _.size(step.attachments) === 0 && step.result.status !== RESULT_STATUS.failed) | ||
) { | ||
return 0; | ||
} | ||
if ( | ||
!step.result || | ||
// Don't log steps that don't have a text/hidden/images/attachments unless they are failed. | ||
// This is for the hooks | ||
(step.hidden && | ||
!step.text && | ||
!step.image && | ||
_.size(step.attachments) === 0 && | ||
step.result.status !== RESULT_STATUS.failed) | ||
) { | ||
return 0; | ||
} | ||
if (step.result.duration) { | ||
scenario.duration += step.result.duration; | ||
step.time = formatDuration(step.result.duration) | ||
} | ||
if (step.result.duration) { | ||
scenario.duration += step.result.duration; | ||
step.time = formatDuration(step.result.duration); | ||
} | ||
if (step.result.status === RESULT_STATUS.passed) { | ||
return scenario.passed++; | ||
} | ||
if (step.result.status.toLowerCase() === RESULT_STATUS.passed) { | ||
return scenario.passed++; | ||
} | ||
if (step.result.status === RESULT_STATUS.failed) { | ||
return scenario.failed++; | ||
} | ||
if (step.result.status.toLowerCase() === RESULT_STATUS.failed) { | ||
return scenario.failed++; | ||
} | ||
if (step.result.status === RESULT_STATUS.notDefined) { | ||
return scenario.notDefined++; | ||
} | ||
if (step.result.status.toLowerCase() === RESULT_STATUS.notDefined) { | ||
return scenario.notDefined++; | ||
} | ||
if (step.result.status === RESULT_STATUS.pending) { | ||
return scenario.pending++; | ||
} | ||
if (step.result.status.toLowerCase() === RESULT_STATUS.pending) { | ||
return scenario.pending++; | ||
} | ||
if (step.result.status === RESULT_STATUS.ambiguous) { | ||
return scenario.ambiguous++; | ||
} | ||
if (step.result.status.toLowerCase() === RESULT_STATUS.ambiguous) { | ||
return scenario.ambiguous++; | ||
} | ||
scenario.skipped++; | ||
}); | ||
scenario.skipped++; | ||
}); | ||
return scenario; | ||
} | ||
return scenario; | ||
} | ||
/** | ||
* Read a template file and return it's content | ||
* @param {string} fileName | ||
* @return {*} Content of the file | ||
* @private | ||
*/ | ||
function _readTemplateFile(fileName) { | ||
if (fileName) { | ||
try { | ||
fs.accessSync(fileName, fs.constants.R_OK); | ||
return fs.readFileSync(fileName, 'utf-8'); | ||
} catch (err) { | ||
return fs.readFileSync(path.join(__dirname, '..', 'templates', fileName), 'utf-8'); | ||
} | ||
} else { | ||
return ''; | ||
} | ||
} | ||
/** | ||
* Read a template file and return it's content | ||
* @param {string} fileName | ||
* @return {*} Content of the file | ||
* @private | ||
*/ | ||
function _readTemplateFile(fileName) { | ||
if (fileName) { | ||
try { | ||
fs.accessSync(fileName, fs.constants.R_OK); | ||
return fs.readFileSync(fileName, 'utf-8'); | ||
} catch (err) { | ||
return fs.readFileSync( | ||
path.join(__dirname, '..', 'templates', fileName), | ||
'utf-8' | ||
); | ||
} | ||
} else { | ||
return ''; | ||
} | ||
} | ||
/** | ||
* Escape html in string | ||
* @param string | ||
* @return {string} | ||
* @private | ||
*/ | ||
function _escapeHtml(string) { | ||
return typeof string === 'string' || string instanceof String | ||
? string.replace(/[^0-9A-Za-z ]/g, chr => '&#' + chr.charCodeAt(0) + ';') | ||
: string | ||
} | ||
/** | ||
* Escape html in string | ||
* @param string | ||
* @return {string} | ||
* @private | ||
*/ | ||
function _escapeHtml(string) { | ||
return typeof string === 'string' || string instanceof String | ||
? string.replace( | ||
/[^0-9A-Za-z ]/g, | ||
(chr) => '&#' + chr.charCodeAt(0) + ';' | ||
) | ||
: string; | ||
} | ||
/** | ||
* Generate the features overview | ||
* @param {object} suite JSON object with all the features and scenarios | ||
* @private | ||
*/ | ||
function _createFeaturesOverviewIndexPage(suite) { | ||
const featuresOverviewIndex = path.resolve(reportPath, INDEX_HTML); | ||
if(suite.customMetadata && options.metadata) { | ||
suite.features.forEach(feature => { | ||
if (!feature.metadata) { | ||
feature.metadata = options.metadata; | ||
} | ||
}); | ||
} | ||
FEATURES_OVERVIEW_TEMPLATE = suite.customMetadata ? | ||
FEATURES_OVERVIEW_CUSTOM_METADATA_TEMPLATE : FEATURES_OVERVIEW_TEMPLATE; | ||
/** | ||
* Generate the features overview | ||
* @param {object} suite JSON object with all the features and scenarios | ||
* @private | ||
*/ | ||
function _createFeaturesOverviewIndexPage(suite) { | ||
const featuresOverviewIndex = path.resolve(reportPath, INDEX_HTML); | ||
if (suite.customMetadata && options.metadata) { | ||
suite.features.forEach((feature) => { | ||
if (!feature.metadata) { | ||
feature.metadata = options.metadata; | ||
} | ||
}); | ||
} | ||
FEATURES_OVERVIEW_TEMPLATE = suite.customMetadata | ||
? FEATURES_OVERVIEW_CUSTOM_METADATA_TEMPLATE | ||
: FEATURES_OVERVIEW_TEMPLATE; | ||
fs.writeFileSync( | ||
featuresOverviewIndex, | ||
_.template(_readTemplateFile(FEATURES_OVERVIEW_INDEX_TEMPLATE))({ | ||
suite: suite, | ||
featuresOverview: _.template(_readTemplateFile(FEATURES_OVERVIEW_TEMPLATE))({ | ||
suite: suite, | ||
_: _ | ||
}), | ||
featuresScenariosOverviewChart: _.template(_readTemplateFile(SCENARIOS_OVERVIEW_CHART_TEMPLATE))({ | ||
overviewPage: true, | ||
scenarios: suite.scenarios, | ||
_: _ | ||
}), | ||
customDataOverview: _.template(_readTemplateFile(CUSTOM_DATA_TEMPLATE))({ | ||
suite: suite, | ||
_: _ | ||
}), | ||
featuresOverviewChart: _.template(_readTemplateFile(FEATURES_OVERVIEW_CHART_TEMPLATE))({ | ||
suite: suite, | ||
_: _ | ||
}), | ||
customStyle: _readTemplateFile(suite.customStyle), | ||
styles: _readTemplateFile(suite.style), | ||
useCDN: suite.useCDN, | ||
genericScript: _readTemplateFile(GENERIC_JS), | ||
pageTitle: pageTitle, | ||
reportName: reportName, | ||
pageFooter: pageFooter | ||
}) | ||
); | ||
} | ||
fs.writeFileSync( | ||
featuresOverviewIndex, | ||
_.template(_readTemplateFile(FEATURES_OVERVIEW_INDEX_TEMPLATE))({ | ||
suite: suite, | ||
featuresOverview: _.template( | ||
_readTemplateFile(FEATURES_OVERVIEW_TEMPLATE) | ||
)({ | ||
suite: suite, | ||
_: _, | ||
}), | ||
featuresScenariosOverviewChart: _.template( | ||
_readTemplateFile(SCENARIOS_OVERVIEW_CHART_TEMPLATE) | ||
)({ | ||
overviewPage: true, | ||
scenarios: suite.scenarios, | ||
_: _, | ||
}), | ||
customDataOverview: _.template(_readTemplateFile(CUSTOM_DATA_TEMPLATE))( | ||
{ | ||
suite: suite, | ||
_: _, | ||
} | ||
), | ||
featuresOverviewChart: _.template( | ||
_readTemplateFile(FEATURES_OVERVIEW_CHART_TEMPLATE) | ||
)({ | ||
suite: suite, | ||
_: _, | ||
}), | ||
customStyle: _readTemplateFile(suite.customStyle), | ||
styles: _readTemplateFile(suite.style), | ||
useCDN: suite.useCDN, | ||
genericScript: _readTemplateFile(GENERIC_JS), | ||
pageTitle: pageTitle, | ||
reportName: reportName, | ||
pageFooter: pageFooter, | ||
}) | ||
); | ||
} | ||
/** | ||
* Generate the feature pages | ||
* @param suite suite JSON object with all the features and scenarios | ||
* @private | ||
*/ | ||
function _createFeatureIndexPages(suite) { | ||
/** | ||
* Generate the feature pages | ||
* @param suite suite JSON object with all the features and scenarios | ||
* @private | ||
*/ | ||
function _createFeatureIndexPages(suite) { | ||
// Set custom metadata overview for the feature | ||
FEATURE_METADATA_OVERVIEW_TEMPLATE = suite.customMetadata | ||
? FEATURE_CUSTOM_METADATA_OVERVIEW_TEMPLATE | ||
: FEATURE_METADATA_OVERVIEW_TEMPLATE; | ||
// Set custom metadata overview for the feature | ||
FEATURE_METADATA_OVERVIEW_TEMPLATE = suite.customMetadata ? | ||
FEATURE_CUSTOM_METADATA_OVERVIEW_TEMPLATE : FEATURE_METADATA_OVERVIEW_TEMPLATE; | ||
suite.features.forEach((feature) => { | ||
const featurePage = path.resolve( | ||
reportPath, | ||
`${FEATURE_FOLDER}/${feature.id}.html` | ||
); | ||
fs.writeFileSync( | ||
featurePage, | ||
_.template(_readTemplateFile(FEATURE_OVERVIEW_INDEX_TEMPLATE))({ | ||
feature: feature, | ||
suite: suite, | ||
featureScenariosOverviewChart: _.template( | ||
_readTemplateFile(SCENARIOS_OVERVIEW_CHART_TEMPLATE) | ||
)({ | ||
overviewPage: false, | ||
feature: feature, | ||
suite: suite, | ||
scenarios: feature.scenarios, | ||
_: _, | ||
}), | ||
featureMetadataOverview: _.template( | ||
_readTemplateFile(FEATURE_METADATA_OVERVIEW_TEMPLATE) | ||
)({ | ||
metadata: feature.metadata, | ||
_: _, | ||
}), | ||
scenarioTemplate: _.template(_readTemplateFile(SCENARIOS_TEMPLATE))({ | ||
suite: suite, | ||
scenarios: feature.elements, | ||
_: _, | ||
}), | ||
useCDN: suite.useCDN, | ||
customStyle: _readTemplateFile(suite.customStyle), | ||
styles: _readTemplateFile(suite.style), | ||
genericScript: _readTemplateFile(GENERIC_JS), | ||
pageTitle: pageTitle, | ||
reportName: reportName, | ||
pageFooter: pageFooter, | ||
plainDescription: plainDescription, | ||
}) | ||
); | ||
// Copy the assets, but first check if they don't exist and not useCDN | ||
if ( | ||
!fs.pathExistsSync(path.resolve(reportPath, 'assets')) && | ||
!suite.useCDN | ||
) { | ||
fs.copySync( | ||
path.resolve( | ||
path.dirname(require.resolve('../package.json')), | ||
'templates/assets' | ||
), | ||
path.resolve(reportPath, 'assets') | ||
); | ||
} | ||
}); | ||
} | ||
suite.features.forEach(feature => { | ||
const featurePage = path.resolve(reportPath, `${ FEATURE_FOLDER }/${ feature.id }.html`); | ||
fs.writeFileSync( | ||
featurePage, | ||
_.template(_readTemplateFile(FEATURE_OVERVIEW_INDEX_TEMPLATE))({ | ||
feature: feature, | ||
suite: suite, | ||
featureScenariosOverviewChart: _.template(_readTemplateFile(SCENARIOS_OVERVIEW_CHART_TEMPLATE))({ | ||
overviewPage: false, | ||
feature: feature, | ||
suite: suite, | ||
scenarios: feature.scenarios, | ||
_: _ | ||
}), | ||
featureMetadataOverview: _.template(_readTemplateFile(FEATURE_METADATA_OVERVIEW_TEMPLATE))({ | ||
metadata: feature.metadata, | ||
_: _ | ||
}), | ||
scenarioTemplate: _.template(_readTemplateFile(SCENARIOS_TEMPLATE))({ | ||
suite: suite, | ||
scenarios: feature.elements, | ||
_: _ | ||
}), | ||
useCDN: suite.useCDN, | ||
customStyle: _readTemplateFile(suite.customStyle), | ||
styles: _readTemplateFile(suite.style), | ||
genericScript: _readTemplateFile(GENERIC_JS), | ||
pageTitle: pageTitle, | ||
reportName: reportName, | ||
pageFooter: pageFooter, | ||
plainDescription: plainDescription | ||
}) | ||
); | ||
// Copy the assets, but first check if they don't exist and not useCDN | ||
if (!fs.pathExistsSync(path.resolve(reportPath, 'assets')) && !suite.useCDN) { | ||
fs.copySync( | ||
path.resolve(path.dirname(require.resolve('../package.json')), 'templates/assets'), | ||
path.resolve(reportPath, 'assets') | ||
); | ||
} | ||
}); | ||
} | ||
/** | ||
* Format the duration to HH:mm:ss.SSS | ||
* | ||
* @param {number} ns | ||
* | ||
* @return {string} | ||
*/ | ||
function formatDuration(ns) { | ||
// `moment.utc(#)` needs ms, we now use device by 1000000 to calculate ns to ms | ||
return moment.utc(durationInMS ? ns : ns / 1000000).format('HH:mm:ss.SSS'); | ||
} | ||
/** | ||
* Format the duration to HH:mm:ss.SSS | ||
* | ||
* @param {number} ns | ||
* | ||
* @return {string} | ||
*/ | ||
function formatDuration(ns) { | ||
// `moment.utc(#)` needs ms, we now use device by 1000000 to calculate ns to ms | ||
return moment.utc(durationInMS ? ns : ns / 1000000).format('HH:mm:ss.SSS'); | ||
} | ||
} | ||
module.exports = { | ||
generate: generateReport | ||
generate: generateReport, | ||
}; |
{ | ||
"name": "multiple-cucumber-html-reporter", | ||
"version": "1.21.5", | ||
"version": "1.21.6", | ||
"description": "Generate beautifull cucumberjs reports for multiple instances (browsers / devices)", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
Sorry, the diff of this file is not supported yet
1990627
3306