diff --git a/README.md b/README.md index ac2568c..37cfedc 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ Please note that all configuration properties are optional. | `sort` | `STRING` | Sorts the test results using the given method. Available sorting methods can be found in the [documentation](https://github.com/Hargne/jest-html-reporter/wiki/Sorting-Methods). | `"default"` | `statusIgnoreFilter` | `STRING` | A comma-separated string of the test result statuses that should be ignored when rendering the report. Available statuses are: `"passed"`, `"pending"`, `"failed"` | `null` | `boilerplate` | `STRING` | The path to a boilerplate file that should be used to render the body of the test results into. `{jesthtmlreporter-content}` within the boilerplate will be replaced with the test results | `null` +| `append` | `BOOLEAN` | If set to true, new test results will be appended to the existing test report | `false` > *The plugin will search for the *styleOverridePath* from the root directory, therefore there is no need to prepend the string with `./` or `../` - You can read more about the themes in the [documentation](https://github.com/Hargne/jest-html-reporter/wiki/Test-Report-Themes). diff --git a/package-lock.json b/package-lock.json index d9577b0..da25c1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "jest-html-reporter", - "version": "2.7.0", + "version": "2.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -677,9 +677,9 @@ }, "dependencies": { "handlebars": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", - "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", "dev": true, "requires": { "neo-async": "^2.6.0", @@ -3792,9 +3792,9 @@ "dev": true }, "handlebars": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", - "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", "dev": true, "requires": { "neo-async": "^2.6.0", diff --git a/package.json b/package.json index 360f084..70bc751 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jest-html-reporter", - "version": "2.7.0", + "version": "2.8.0", "description": "Jest test results processor for generating a summary in HTML", "main": "dist/main", "unpkg": "dist/main.min.js", diff --git a/src/config.js b/src/config.js index f920548..1b7c55f 100644 --- a/src/config.js +++ b/src/config.js @@ -140,6 +140,13 @@ const getSort = () => const getStatusIgnoreFilter = () => process.env.JEST_HTML_REPORTER_STATUS_FILTER || config.statusIgnoreFilter || null; +/** + * Returns whether or not new reports should be Appended to existing report + * @return {Boolean} + */ +const getAppend = () => + process.env.JEST_HTML_REPORTER_APPEND || config.append || false; + module.exports = { config, setup, @@ -160,4 +167,5 @@ module.exports = { getDateFormat, getSort, getStatusIgnoreFilter, + getAppend, }; diff --git a/src/reportGenerator.js b/src/reportGenerator.js index 033e578..7297a7d 100644 --- a/src/reportGenerator.js +++ b/src/reportGenerator.js @@ -20,6 +20,7 @@ class ReportGenerator { const fileDestination = this.config.getOutputFilepath(); const useCssFile = this.config.shouldUseCssFile(); const shouldGetStylesheetContent = this.config.shouldGetStylesheetContent(); + const append = this.config.getAppend(); let stylesheetPath = null; let stylesheetContent = null; @@ -39,10 +40,13 @@ class ReportGenerator { stylesheet, stylesheetPath, })) - .then(xmlBuilderOutput => utils.writeFile({ + .then(xmlBuilderOutput => (append ? utils.appendFile({ filePath: fileDestination, content: xmlBuilderOutput, - })) + }) : utils.writeFile({ + filePath: fileDestination, + content: xmlBuilderOutput, + }))) .then(() => utils.logMessage({ type: 'success', msg: `Report generated (${fileDestination})`, diff --git a/src/utils.js b/src/utils.js index 224b767..faa5505 100644 --- a/src/utils.js +++ b/src/utils.js @@ -42,6 +42,55 @@ const writeFile = ({ filePath, content }) => new Promise((resolve, reject) => { }); }); +/** + * Appends a file at the given destination + * @param {String} filePath + * @param {Any} content + */ +const appendFile = ({ filePath, content }) => new Promise((resolve, reject) => { + mkdirp(path.dirname(filePath), (mkdirpError) => { + if (mkdirpError) { + return reject(new Error(`Something went wrong when creating the folder: ${mkdirpError}`)); + } + + // Check if the file exists or not + return fs.readFile(filePath, 'utf8', (err, existingContent) => { + let parsedContent = content; + // The file exists - we need to strip all unecessary html + if (!err) { + const contentSearch = /(.*?)<\/body>/gm.exec(content); + if (contentSearch) { + const [strippedContent] = contentSearch; + parsedContent = strippedContent; + } + // Then we need to add the stripped content just before the tag + if (existingContent) { + let newContent = existingContent; + const closingBodyTag = /<\/body>/gm.exec(existingContent); + const indexOfClosingBodyTag = closingBodyTag ? closingBodyTag.index : 0; + + newContent = [existingContent.slice(0, indexOfClosingBodyTag), parsedContent, existingContent.slice(indexOfClosingBodyTag)] + .join(''); + + return fs.writeFile(filePath, newContent, (writeFileError) => { + if (writeFileError) { + return reject(new Error(`Something went wrong when creating the file: ${writeFileError}`)); + } + return resolve(filePath); + }); + } + } + + return fs.appendFile(filePath, parsedContent, (writeFileError) => { + if (writeFileError) { + return reject(new Error(`Something went wrong when appending the file: ${writeFileError}`)); + } + return resolve(filePath); + }); + }); + }); +}); + /** * Reads and returns the content of a given file * @param {String} filePath @@ -90,6 +139,7 @@ const sortAlphabetically = ({ a, b, reversed }) => { module.exports = { logMessage, writeFile, + appendFile, getFileContent, createHtmlBase, sortAlphabetically, diff --git a/style/darkTheme.css b/style/darkTheme.css index 1bdd828..79b8b60 100644 --- a/style/darkTheme.css +++ b/style/darkTheme.css @@ -10,6 +10,9 @@ body { padding: 3rem; font-size: 0.85rem; } +#jesthtml-content { + margin-bottom: 2rem; +} header { display: flex; align-items: center; diff --git a/style/defaultTheme.css b/style/defaultTheme.css index 6289160..668ae25 100644 --- a/style/defaultTheme.css +++ b/style/defaultTheme.css @@ -9,6 +9,9 @@ body { padding: 1rem; font-size: 0.85rem; } +#jesthtml-content { + margin-bottom: 2rem; +} header { display: flex; align-items: center; diff --git a/style/lightTheme.css b/style/lightTheme.css index febac46..28fb411 100644 --- a/style/lightTheme.css +++ b/style/lightTheme.css @@ -9,6 +9,9 @@ body { padding: 3rem; font-size: 0.85rem; } +#jesthtml-content { + margin-bottom: 2rem; +} header { display: flex; align-items: center;