jest-html-reporter
Advanced tools
Comparing version 0.2.0 to 0.3.0
121
index.js
@@ -6,3 +6,2 @@ const path = require('path'); | ||
const stripAnsi = require('strip-ansi'); | ||
const defaultStylesheet = require('./style'); | ||
@@ -21,3 +20,2 @@ | ||
} | ||
/** | ||
@@ -28,29 +26,20 @@ * Creates a file at the given destination | ||
*/ | ||
const writeFile = (filePath, content) => mkdirp(path.dirname(filePath), (err) => { | ||
if (err) { | ||
return console.log(`Jest-HTML-Reporter: Something went wrong when creating the file: ${err}`); | ||
} | ||
return fs.writeFile(filePath, content); | ||
const writeFile = (filePath, content) => new Promise((resolve, reject) => { | ||
mkdirp(path.dirname(filePath), (err) => !err ? resolve(fs.writeFile(filePath, content)) : reject(`Something went wrong when creating the file: ${err}`)); | ||
}); | ||
/** | ||
* Fetches the stylesheet to be imported in the test report. | ||
* If the styleOverridePath fil cannot be found, it will respond with the default stylesheet. | ||
* Returns the stylesheet to be imported in the test report. | ||
* If styleOverridePath is not defined, it will return the default stylesheet (style.js). | ||
* @param {String} filePath | ||
* @return {Promise} | ||
*/ | ||
const getStylesheet = () => { | ||
return new Promise((resolve, reject) => { | ||
// If the styleOverridePath has not been set, return the default stylesheet. | ||
if (!config.styleOverridePath) { resolve(defaultStylesheet); } | ||
// Attempt to read the given file | ||
fs.readFile(config.styleOverridePath, 'utf8', (err, content) => { | ||
// If there were no errors, return the content of the given file. | ||
// Otherwise resolve the promise with the default stylesheet. | ||
const response = !err ? content : defaultStylesheet; | ||
resolve(response); | ||
}); | ||
const getStylesheet = () => new Promise((resolve, reject) => { | ||
// If the styleOverridePath has not been set, return the default stylesheet (style.js). | ||
if (!config.styleOverridePath) { return resolve(defaultStylesheet); } | ||
// Attempt to read the given file | ||
fs.readFile(config.styleOverridePath, 'utf8', (err, content) => { | ||
// If there were no errors, return the content of the given file. | ||
return !err ? resolve(content) : reject(`Could not find the specified styleOverridePath: '${config.styleOverridePath}'`); | ||
}); | ||
}; | ||
}); | ||
/** | ||
@@ -72,30 +61,27 @@ * Sets up a basic HTML page to apply the content to | ||
}); | ||
/** | ||
* Returns a HTML containing the test report. | ||
* @param {String} stylesheet | ||
* @param {Object} data The test result data | ||
* @param {Object} testData The test result data | ||
* @return {xmlbuilder} | ||
*/ | ||
const renderHTMLReport = ({ stylesheet, data }) => { | ||
// Create HTML and Body tags | ||
const renderHTMLReport = (testData, stylesheet) => new Promise((resolve, reject) => { | ||
// Create an xmlbuilder object with HTML and Body tags | ||
const htmlOutput = createHtml(stylesheet); | ||
// Timestamp | ||
htmlOutput.ele('div', { id: 'timestamp' }, ` | ||
Start: ${(new Date(data.startTime)).toLocaleString()} | ||
`); | ||
htmlOutput.ele('div', { id: 'timestamp' }, `Start: ${(new Date(testData.startTime)).toLocaleString()}`); | ||
// Test Summary | ||
htmlOutput.ele('div', { id: 'summary' }, ` | ||
${data.numTotalTests} tests / | ||
${data.numPassedTests} passed / | ||
${data.numFailedTests} failed / | ||
${data.numPendingTests} skipped | ||
${testData.numTotalTests} tests / | ||
${testData.numPassedTests} passed / | ||
${testData.numFailedTests} failed / | ||
${testData.numPendingTests} pending | ||
`); | ||
// Loop through each suite | ||
data.testResults.forEach((suite) => { | ||
if (suite.testResults.length <= 0) { return; } | ||
// Suite File Path | ||
// Loop through each test suite | ||
testData.testResults.forEach((suite) => { | ||
if (!suite.testResults || suite.testResults.length <= 0) { return; } | ||
// Suite filepath location | ||
htmlOutput.ele('div', { class: 'suite-info' }, ` | ||
${suite.testFilePath} | ||
(${(suite.perfStats.end - suite.perfStats.start) / 1000}s) | ||
${suite.testFilePath} (${(suite.perfStats.end - suite.perfStats.start) / 1000}s) | ||
`); | ||
@@ -107,24 +93,22 @@ // Suite Test Table | ||
const testTr = suiteTable.ele('tr', { class: test.status }); | ||
// Suite Name(s) | ||
testTr.ele('td', { class: 'suite' }, test.ancestorTitles.join(' > ')); | ||
// Test name | ||
const testTitleTd = testTr.ele('td', { class: 'test' }, test.title); | ||
// Test Failure Messages | ||
if (test.failureMessages && config.includeFailureMsg) { | ||
failureMsgDiv = testTitleTd.ele('div', { class: 'failureMessages' }) | ||
test.failureMessages.forEach((failureMsg) => { | ||
failureMsgDiv.ele('p', { class: 'failureMsg' }, stripAnsi(failureMsg)); | ||
}); | ||
} | ||
// Test Result | ||
testTr.ele('td', { class: 'result' }, (test.status === 'passed') ? | ||
`${test.status} in ${test.duration / 1000}s` | ||
: test.status | ||
); | ||
// Suite Name(s) | ||
testTr.ele('td', { class: 'suite' }, test.ancestorTitles.join(' > ')); | ||
// Test name | ||
const testTitleTd = testTr.ele('td', { class: 'test' }, test.title); | ||
// Test Failure Messages | ||
if (test.failureMessages && config.includeFailureMsg) { | ||
failureMsgDiv = testTitleTd.ele('div', { class: 'failureMessages' }) | ||
test.failureMessages.forEach((failureMsg) => { | ||
failureMsgDiv.ele('p', { class: 'failureMsg' }, stripAnsi(failureMsg)); | ||
}); | ||
} | ||
// Test Result | ||
testTr.ele('td', { class: 'result' }, (test.status === 'passed') ? | ||
`${test.status} in ${test.duration / 1000}s` | ||
: test.status | ||
); | ||
}); | ||
}); | ||
// Send back the rendered HTML | ||
return htmlOutput; | ||
}; | ||
return resolve(htmlOutput); | ||
}); | ||
/** | ||
@@ -134,11 +118,10 @@ * Main Export | ||
module.exports = (testResult) => { | ||
getStylesheet().then(stylesheet => { | ||
// Render the HTML report | ||
const htmlReport = renderHTMLReport({ stylesheet, data: testResult }); | ||
// Write the report to the destination file | ||
writeFile(config.outputPath || path.join(process.cwd(), 'test-report.html'), htmlReport); | ||
// Finish up | ||
console.log('Jest HTML report generated.'); | ||
return testResult; | ||
}); | ||
// Define location for report output | ||
const reportOutputLocation = config.outputPath || path.join(process.cwd(), 'test-report.html'); | ||
// Run | ||
getStylesheet() | ||
.then(renderHTMLReport.bind(null, testResult)) | ||
.then(writeFile.bind(null, reportOutputLocation)) | ||
.then(() => console.log('\x1b[32m', `jest-html-reporter >> Report generated (${reportOutputLocation})`)) | ||
.catch(error => console.log('\x1b[31m', `jest-html-reporter [error] >> ${error}`)); | ||
}; |
{ | ||
"name": "jest-html-reporter", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Jest test results processor for generating a summary in HTML", | ||
@@ -17,2 +17,3 @@ "main": "index.js", | ||
"reporter", | ||
"report", | ||
"plugin" | ||
@@ -28,3 +29,3 @@ ], | ||
"mkdirp": "0.5.1", | ||
"strip-ansi": "^3.0.1", | ||
"strip-ansi": "3.0.1", | ||
"xmlbuilder": "8.2.2" | ||
@@ -31,0 +32,0 @@ }, |
85
style.js
@@ -1,70 +0,17 @@ | ||
module.exports = () => ` | ||
html, body { | ||
font-family: Arial, Helvetica, sans-serif; | ||
font-size: 1rem; | ||
margin: 0; | ||
padding: 0; | ||
color: #333; | ||
} | ||
body { | ||
padding: 1rem 2rem; | ||
font-size: 0.85rem; | ||
} | ||
#timestamp { | ||
font-weight: bold; | ||
color: #666; | ||
margin-bottom: 0.5rem; | ||
} | ||
#summary { | ||
color: #999; | ||
margin-bottom: 1em; | ||
} | ||
.suite-info { | ||
padding: 1em; | ||
background-color: #eee; | ||
border-bottom: 2px solid #999; | ||
font-weight: bold; | ||
color: #999; | ||
} | ||
.suite-table { | ||
width: 100%; | ||
font-size: 0.85rem; | ||
margin-bottom: 1em; | ||
} | ||
.suite-table td { | ||
padding: 0.5rem; | ||
} | ||
.suite-table tr.passed { | ||
background-color: #DFF2BF; | ||
color: #4F8A10; | ||
} | ||
.suite-table tr.pending { | ||
background-color: #FEEFB3; | ||
color: #9F6000; | ||
} | ||
.suite-table tr.failed { | ||
background-color: #FFBABA; | ||
color: #D8000C; | ||
} | ||
.suite-table td { | ||
font-size: 0.85rem; | ||
border-bottom: 1px solid #aaa; | ||
vertical-align: top; | ||
} | ||
.suite-table td.suite { | ||
font-weight: bold; | ||
width: 20%; | ||
} | ||
.suite-table td.test { | ||
font-style: italic; | ||
width: 60%; | ||
} | ||
.suite-table td.test .failureMsg { | ||
font-weight: bold; | ||
font-size: 0.7rem; | ||
} | ||
.suite-table td.result { | ||
width: 20%; | ||
text-align: right; | ||
} | ||
module.exports = () =>` | ||
html,body {font-family:Arial,Helvetica,sans-serif;font-size:1rem;margin:0;padding:0;color:#333;} | ||
body {padding:1rem;2rem;font-size:0.85rem;} | ||
#timestamp {font-weight:bold;color:#666;margin-bottom:0.5rem;} | ||
#summary {color:#999;margin-bottom:1em;} | ||
.suite-info {padding:1em;background-color:#eee;border-bottom:2px solid #999;font-weight:bold;color:#999;} | ||
.suite-table {width:100%;font-size:0.85rem;margin-bottom:1em;} | ||
.suite-table td {padding:0.5rem;} | ||
.suite-table tr.passed {background-color:#DFF2BF;color:#4F8A10;} | ||
.suite-table tr.pending {background-color:#FEEFB3;color:#9F6000;} | ||
.suite-table tr.failed {background-color:#FFBABA;color:#D8000C;} | ||
.suite-table td {font-size:0.85rem;border-bottom:1px solid #aaa;vertical-align:top;} | ||
.suite-table td.suite {font-weight:bold;width:20%;} | ||
.suite-table td.test {font-style:italic;width:60%;} | ||
.suite-table td.test .failureMsg {font-weight:bold;font-size:0.7rem;} | ||
.suite-table td.result {width:20%;text-align:right;} | ||
`; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9455
136
Updatedstrip-ansi@3.0.1