๐Ÿ“… You're Invited: Meet the Socket team at RSAC (April 28 โ€“ย May 1).RSVP โ†’
Socket
Sign inDemoInstall
Socket

jest-html-reporter

Package Overview
Dependencies
Maintainers
1
Versions
72
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jest-html-reporter - npm Package Compare versions

Comparing version

to
4.0.0

2

dist/index.js

@@ -1,1 +0,1 @@

"use strict";var e=require("dateformat"),t=require("fs"),s=require("mkdirp"),a=require("path"),i=require("strip-ansi"),l=require("xmlbuilder");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=n(e),r=n(t),u=n(s),c=n(a),d=n(i),g=n(l);const h=e=>{const t=[],s=[],a=[];return e.forEach((e=>{const i=[],l=[],n=[];e.testResults.forEach((e=>{"pending"===e.status?i.push(e):"failed"===e.status?l.push(e):n.push(e)})),i.length>0&&t.push({...e,testResults:i}),l.length>0&&s.push({...e,testResults:l}),n.length>0&&a.push({...e,testResults:n})})),[].concat(t,s,a)},f=e=>(e&&e.sort(((e,t)=>t.perfStats.end-t.perfStats.start-(e.perfStats.end-e.perfStats.start))),e),p=e=>(e&&e.sort(((e,t)=>e.perfStats.end-e.perfStats.start-(t.perfStats.end-t.perfStats.start))),e),T=e=>{if(e){const t=e.sort(((e,t)=>E(e.testFilePath,t.testFilePath,!0)));return t.forEach((e=>{e.testResults.sort(((e,t)=>E(e.ancestorTitles.join(" "),t.ancestorTitles.join(" "),!0))),e.testResults.sort(((e,t)=>E(e.title,t.title,!0)))})),t}return e},m=e=>{if(e){const t=e.sort(((e,t)=>E(e.testFilePath,t.testFilePath)));return t.forEach((e=>{e.testResults.sort(((e,t)=>E(e.ancestorTitles.join(" "),t.ancestorTitles.join(" ")))),e.testResults.sort(((e,t)=>E(e.title,t.title)))})),t}return e},E=(e,t,s=!1)=>!s&&e<t||s&&e>t?-1:!s&&e>t||s&&e<t?1:0;class S{constructor(e){this.testData=e.testData,this.jestConfig=e.jestConfig,this.consoleLogList=e.consoleLogs,this.setupConfig(e.options)}async generate(){try{const e=await this.renderTestReport(),t=this.replaceRootDirInPath(this.jestConfig?this.jestConfig.rootDir:"",this.getConfigValue("outputPath"));await u.default(c.default.dirname(t));let s=!0;if(this.getConfigValue("append")){r.default.existsSync(t)&&(await this.appendToFile(t,e.content.toString()),s=!1)}return s&&r.default.writeFileSync(t,e.fullHtml.toString()),this.logMessage("success",`Report generated (${t})`),e.fullHtml}catch(e){this.logMessage("error",e)}}async renderTestReport(){const e=await this.renderTestReportContent();if(this.getConfigValue("boilerplate")){const t=this.replaceRootDirInPath(this.jestConfig?this.jestConfig.rootDir:"",this.getConfigValue("boilerplate")),s=r.default.readFileSync(t,"utf8");return{content:e.toString(),fullHtml:s.replace("{jesthtmlreporter-content}",e&&e.toString())}}const t=g.default.create({html:{}}),s=t.ele("head");s.ele("meta",{charset:"utf-8"}),s.ele("title",{},this.getConfigValue("pageTitle"));let a=c.default.join(__dirname,`../style/${this.getConfigValue("theme")}.css`);this.getConfigValue("styleOverridePath")&&(a=this.getConfigValue("styleOverridePath"));if(!this.getConfigValue("useCssFile")&&!this.getConfigValue("styleOverridePath")){const e=r.default.readFileSync(a,"utf8");s.raw(`<style type="text/css">${e}</style>`)}else s.ele("link",{rel:"stylesheet",type:"text/css",href:a});const i=t.ele("body");return e&&i.raw(e.toString()),this.getConfigValue("customScriptPath")&&i.raw(`<script src="${this.getConfigValue("customScriptPath")}"><\/script>`),{fullHtml:t.toString(),content:e.toString()}}renderTestSuiteHeader(e,t,s){const a=`collapsible-${s}`;e.ele("input",{id:a,type:"checkbox",class:"toggle",checked:this.getConfigValue("collapseSuitesByDefault")?null:"checked"});const i=e.ele("label",{for:a}).ele("div",{class:"suite-info"});i.ele("div",{class:"suite-path"},t.testFilePath);const l=(t.perfStats.end-t.perfStats.start)/1e3,n=["suite-time"];l>this.getConfigValue("executionTimeWarningThreshold")&&n.push("warn"),i.ele("div",{class:n.join(" ")},`${l}s`)}async renderTestReportContent(){try{if(!this.testData||0===Object.entries(this.testData).length)throw Error("No test data provided");const e=g.default.begin().element("div",{class:"jesthtml-content"}),t=e.ele("header");t.ele("h1",{id:"title"},this.getConfigValue("pageTitle"));const s=this.getConfigValue("logo");s&&t.ele("img",{id:"logo",src:s});const a=e.ele("div",{id:"metadata-container"});if(this.testData.startTime&&!isNaN(this.testData.startTime)){const e=new Date(this.testData.startTime);if(e){const t=o.default(e,this.getConfigValue("dateFormat"));a.ele("div",{id:"timestamp"},`Started: ${t}`)}}const i=a.ele("div",{id:"summary"}),l=i.ele("div",{id:"suite-summary"}),n=(e,t)=>[`summary-${e}`,t>0?"":" summary-empty"].join(" ");l.ele("div",{class:"summary-total"},`Suites (${this.testData.numTotalTestSuites})`),l.ele("div",{class:n("passed",this.testData.numPassedTestSuites)},`${this.testData.numPassedTestSuites} passed`),l.ele("div",{class:n("failed",this.testData.numFailedTestSuites)},`${this.testData.numFailedTestSuites} failed`),l.ele("div",{class:n("pending",this.testData.numPendingTestSuites)},`${this.testData.numPendingTestSuites} pending`),this.testData.snapshot&&this.testData.snapshot.unchecked>0&&this.getConfigValue("includeObsoleteSnapshots")&&l.ele("div",{class:"summary-obsolete-snapshots"},`${this.testData.snapshot.unchecked} obsolete snapshots`);const r=i.ele("div",{id:"test-summary"});r.ele("div",{class:"summary-total"},`Tests (${this.testData.numTotalTests})`),r.ele("div",{class:n("passed",this.testData.numPassedTests)},`${this.testData.numPassedTests} passed`),r.ele("div",{class:n("failed",this.testData.numFailedTests)},`${this.testData.numFailedTests} failed`),r.ele("div",{class:n("pending",this.testData.numPendingTests)},`${this.testData.numPendingTests} pending`);const u=((e,t)=>{switch(t&&t.toLowerCase()){case"status":return h(e);case"executiondesc":return f(e);case"executionasc":return p(e);case"titledesc":return T(e);case"titleasc":return m(e);default:return e}})(this.testData.testResults,this.getConfigValue("sort")),c=this.getConfigValue("statusIgnoreFilter");let d=[];return c&&(d=c.replace(/\s/g,"").toLowerCase().split(",")),u&&u.forEach(((t,s)=>{const a=e.ele("div",{id:`suite-${s+1}`,class:"suite-container"});this.renderTestSuiteHeader(a,t,s);const i=a.ele("div",{class:"suite-tests"});if(!t.testResults||t.testResults.length<=0){if(t.failureMessage&&this.getConfigValue("includeSuiteFailure")){i.ele("div",{class:"test-result failed"}).ele("div",{class:"failureMessages suiteFailure"}," ").ele("pre",{class:"failureMsg"},this.sanitizeOutput(t.failureMessage))}}else t.testResults.filter((e=>!d.includes(e.status))).forEach((async e=>{const t=i.ele("div",{class:`test-result ${e.status}`}),s=t.ele("div",{class:"test-info"});if(s.ele("div",{class:"test-suitename"},e.ancestorTitles&&e.ancestorTitles.length>0?e.ancestorTitles.join(" > "):" "),s.ele("div",{class:"test-title"},e.title),s.ele("div",{class:"test-status"},e.status),s.ele("div",{class:"test-duration"},e.duration/1e3+"s"),e.failureMessages&&e.failureMessages.length>0&&this.getConfigValue("includeFailureMsg")){const s=t.ele("div",{class:"failureMessages"}," ");e.failureMessages.map((e=>this.getConfigValue("includeStackTrace")?e:e.split(/\n\s+at/)[0].trim().replace(/\n+$/,""))).forEach((e=>{s.ele("pre",{class:"failureMsg"},this.sanitizeOutput(e))}))}})),this.consoleLogList&&this.consoleLogList.length>0&&this.getConfigValue("includeConsoleLog")&&this.renderSuiteConsoleLogs(t,a),t.snapshot&&t.snapshot.unchecked>0&&this.getConfigValue("includeObsoleteSnapshots")&&this.renderSuiteObsoleteSnapshots(a,t)})),e}catch(e){this.logMessage("error",e)}}renderSuiteConsoleLogs(e,t){const s=this.consoleLogList.find((t=>t.filePath===e.testFilePath));if(s&&s.logs.length>0){const e=t.ele("div",{class:"suite-consolelog"});e.ele("div",{class:"suite-consolelog-header"},"Console Log"),s.logs.forEach((t=>{const s=e.ele("div",{class:"suite-consolelog-item"});s.ele("pre",{class:"suite-consolelog-item-origin"},this.sanitizeOutput(t.origin)),s.ele("pre",{class:"suite-consolelog-item-message"},this.sanitizeOutput(t.message))}))}}renderSuiteObsoleteSnapshots(e,t){const s=e.ele("div",{class:"suite-obsolete-snapshots"});s.ele("div",{class:"suite-obsolete-snapshots-header"},"Obsolete snapshots");s.ele("div",{class:"suite-obsolete-snapshots-item"}).ele("pre",{class:"suite-obsolete-snapshots-item-message"},t.snapshot.uncheckedKeys.join("\n"))}setupConfig(e){const{append:t,boilerplate:s,collapseSuitesByDefault:a,customScriptPath:i,dateFormat:l,executionTimeWarningThreshold:n,logo:o,includeConsoleLog:u,includeFailureMsg:d,includeStackTrace:g,includeSuiteFailure:h,includeObsoleteSnapshots:f,outputPath:p,pageTitle:T,theme:m,sort:E,statusIgnoreFilter:S,styleOverridePath:R,useCssFile:V}=e||{};this.config={append:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_APPEND",configValue:t},boilerplate:{defaultValue:null,environmentVariable:"JEST_HTML_REPORTER_BOILERPLATE",configValue:s},collapseSuitesByDefault:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_COLLAPSE_SUITES_BY_DEFAULT",configValue:a},customScriptPath:{defaultValue:null,environmentVariable:"JEST_HTML_REPORTER_CUSTOM_SCRIPT_PATH",configValue:i},dateFormat:{defaultValue:"yyyy-mm-dd HH:MM:ss",environmentVariable:"JEST_HTML_REPORTER_DATE_FORMAT",configValue:l},executionTimeWarningThreshold:{defaultValue:5,environmentVariable:"JEST_HTML_REPORTER_EXECUTION_TIME_WARNING_THRESHOLD",configValue:n},logo:{defaultValue:null,environmentVariable:"JEST_HTML_REPORTER_LOGO",configValue:o},includeFailureMsg:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_INCLUDE_FAILURE_MSG",configValue:d},includeStackTrace:{defaultValue:!0,environmentVariable:"JEST_HTML_REPORTER_INCLUDE_STACK_TRACE",configValue:g},includeSuiteFailure:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_INCLUDE_SUITE_FAILURE",configValue:h},includeObsoleteSnapshots:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_INCLUDE_OBSOLETE_SNAPSHOTS",configValue:f},includeConsoleLog:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_INCLUDE_CONSOLE_LOG",configValue:u},outputPath:{defaultValue:c.default.join(process.cwd(),"test-report.html"),environmentVariable:"JEST_HTML_REPORTER_OUTPUT_PATH",configValue:p},pageTitle:{defaultValue:"Test Report",environmentVariable:"JEST_HTML_REPORTER_PAGE_TITLE",configValue:T},theme:{defaultValue:"defaultTheme",environmentVariable:"JEST_HTML_REPORTER_THEME",configValue:m},sort:{defaultValue:null,environmentVariable:"JEST_HTML_REPORTER_SORT",configValue:E},statusIgnoreFilter:{defaultValue:null,environmentVariable:"JEST_HTML_REPORTER_STATUS_FILTER",configValue:S},styleOverridePath:{defaultValue:null,environmentVariable:"JEST_HTML_REPORTER_STYLE_OVERRIDE_PATH",configValue:R},useCssFile:{defaultValue:!1,environmentVariable:"JEST_HTML_REPORTER_USE_CSS_FILE",configValue:V}};try{const e=r.default.readFileSync(c.default.join(process.cwd(),"jesthtmlreporter.config.json"),"utf8");if(e){const t=JSON.parse(e);for(const e of Object.keys(t))e in this.config&&(this.config[e].configValue=t[e]);return this.config}}catch(e){}try{const e=r.default.readFileSync(c.default.join(process.cwd(),"package.json"),"utf8");if(e){const t=JSON.parse(e)["jest-html-reporter"];for(const e of Object.keys(t))e in this.config&&(this.config[e].configValue=t[e]);return this.config}}catch(e){}}getConfigValue(e){const t=this.config[e];if(t)return process.env[t.environmentVariable]?process.env[t.environmentVariable]:t.configValue??t.defaultValue}async appendToFile(e,t){let s=t;const a=r.default.readFileSync(e,"utf8"),i=/<body>(.*?)<\/body>/gm.exec(t);if(i){const[e]=i;s=e}let l=a;const n=/<\/body>/gm.exec(a),o=n?n.index:0;return l=[a.slice(0,o),s,a.slice(o)].join(""),r.default.writeFileSync(e,l)}replaceRootDirInPath(e,t){return/^<rootDir>/.test(t)?c.default.resolve(e,c.default.normalize("./"+t.substring(9))):t}logMessage(e,t){const s={default:"%s",success:"%s",error:"%s"},a=s[e]?s[e]:s.default,i=`jest-html-reporter >> ${t}`;return void 0===process.env.JEST_WORKER_ID&&console.log(a,i),{logColor:a,logMsg:i}}sanitizeOutput(e){return d.default(e.replace(/(\x1b\[\d*m)/g,"").replace(/([^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFC\u{10000}-\u{10FFFF}])/gu,""))}}const R=e=>new S(e).generate();module.exports=function(e,t){const s=[];if(Object.prototype.hasOwnProperty.call(e,"testResults")){const s=e;return R({testData:s,options:t}),s}this.onTestResult=(e,t)=>{t.console&&s.push({filePath:t.testFilePath,logs:t.console})},this.onRunComplete=(a,i)=>R({testData:i,options:t,jestConfig:e,consoleLogs:s})};
"use strict";var e=require("dateformat"),t=require("fs"),s=require("mkdirp"),i=require("path"),n=require("xmlbuilder"),a=require("strip-ansi");function o(e,t){const s={default:"%s",success:"%s",error:"%s"},i=s[e]?s[e]:s.default,n=`jest-html-reporter >> ${t}`;return void 0===process.env.JEST_WORKER_ID&&console.log(i,n),{logColor:i,logMsg:n}}function r(e){return o("error",e instanceof Error?e.message:"An error occurred")}function l(e){if("string"!=typeof e)throw new TypeError("Input must be a string");return a(e).replace(/[^\t\n\r\x20-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/gu,"")}function u(e,t){if("string"!=typeof e||"string"!=typeof t)throw new TypeError("Both rootDir and filePath must be strings.");return t.startsWith("<rootDir>")?i.resolve(e,i.normalize(`./${t.slice(9)}`)):t}function c(e,t,s=!1){return!s&&e<t||s&&e>t?-1:!s&&e>t||s&&e<t?1:0}function d(e){return"boolean"==typeof e?e:"string"==typeof e&&"true"===e}function h(e){if("string"==typeof e)return e}const g=["pending","failed","passed"];const p=(e,t)=>{const s={pending:[],failed:[],passed:[]},i=[];e.forEach((e=>{const t=[],n=[],a=[],o=[];e.testResults.forEach((e=>{"pending"===e.status?t.push(e):"failed"===e.status?n.push(e):"passed"===e.status?a.push(e):o.push(e)})),t.length>0&&s.pending.push({...e,testResults:t}),n.length>0&&s.failed.push({...e,testResults:n}),a.length>0&&s.passed.push({...e,testResults:a}),o.length>0&&i.push({...e,testResults:o})}));const n=[...t||[],...["pending","failed","passed"].filter((e=>!(t||[]).includes(e)))],a=Object.entries(s).sort((([e],[t])=>n.indexOf(e)-n.indexOf(t))).flatMap((([,e])=>e));return[...a,...i]},f=e=>(e&&e.sort(((e,t)=>t.perfStats.end-t.perfStats.start-(e.perfStats.end-e.perfStats.start))),e),m=e=>(e&&e.sort(((e,t)=>e.perfStats.end-e.perfStats.start-(t.perfStats.end-t.perfStats.start))),e),y=e=>{if(e){const t=e.sort(((e,t)=>c(e.testFilePath,t.testFilePath,!0)));return t.forEach((e=>{e.testResults.sort(((e,t)=>c(e.ancestorTitles.join(" "),t.ancestorTitles.join(" "),!0))),e.testResults.sort(((e,t)=>c(e.title,t.title,!0)))})),t}return e},S=e=>{if(e){const t=e.sort(((e,t)=>c(e.testFilePath,t.testFilePath)));return t.forEach((e=>{e.testResults.sort(((e,t)=>c(e.ancestorTitles.join(" "),t.ancestorTitles.join(" ")))),e.testResults.sort(((e,t)=>c(e.title,t.title)))})),t}return e},T={append:!1,boilerplate:void 0,collapseSuitesByDefault:!1,customScriptPath:void 0,dateFormat:"yyyy-mm-dd HH:MM:ss",executionTimeWarningThreshold:5,includeConsoleLog:!1,includeFailureMsg:!1,includeStackTrace:!0,includeSuiteFailure:!1,includeObsoleteSnapshots:!1,logo:void 0,outputPath:i.join(process.cwd(),"test-report.html"),pageTitle:"Test Report",sort:void 0,statusIgnoreFilter:void 0,styleOverridePath:void 0,theme:"defaultTheme",useCssFile:!1};function v(e){try{if(t.existsSync(e))return JSON.parse(t.readFileSync(e,"utf8"))}catch{return{}}return{}}const C={append:d,boilerplate:h,collapseSuitesByDefault:d,customScriptPath:h,dateFormat:h,executionTimeWarningThreshold:function(e){return"number"==typeof e?e:"string"==typeof e?Number(e):NaN},includeConsoleLog:d,includeFailureMsg:d,includeStackTrace:d,includeSuiteFailure:d,includeObsoleteSnapshots:d,logo:h,outputPath:h,pageTitle:h,sort:h,statusIgnoreFilter:h,styleOverridePath:h,theme:h,useCssFile:d};function F(e){return"object"!=typeof e||null===e?{}:Object.keys(T).reduce(((t,s)=>{const i=C[s];if(i&&"function"==typeof i&&s in e){const n=i(e[s]);if(void 0!==n)return{...t,[s]:n}}return t}),{})}class D{testData;consoleLogList;jestConfig;config;constructor(e){this.testData=e.testData,this.jestConfig=e.jestConfig,this.consoleLogList=e.consoleLogs||[],this.config=function(e){const t=Object.keys(T).reduce(((e,t)=>{const s=function(e){return`JEST_HTML_REPORTER_${e.replace(/([a-z])([A-Z])/g,"$1_$2").toUpperCase()}`}(t);return void 0!==process.env[s]?{...e,[t]:process.env[s]}:e}),{}),s=v(i.join(process.cwd(),"jesthtmlreporter.config.json")),n=v(i.join(process.cwd(),"package.json"))?.jest||{};return{...T,...F(n),...F(s),...F(e),...F(t)}}(e.options)}async generate(){try{const e=await this.renderTestReport(),n=u(this.jestConfig?this.jestConfig.rootDir:"",this.getConfigValue("outputPath"));await s(i.dirname(n));let a=!0;if(this.getConfigValue("append")){t.existsSync(n)&&(await async function(e,s){try{await t.promises.access(e);const i=await t.promises.readFile(e,"utf8"),n=/<body>(.*?)<\/body>/s.exec(s),a=n?n[1]:s,o=/<\/body>/i.exec(i),r=o?o.index:0,l=[i.slice(0,r),a,i.slice(r)].join("");await t.promises.writeFile(e,l,"utf8")}catch(e){let t="An unknown error occurred while appending to the file";throw e instanceof Error&&(t=e.message),new Error(t)}}(n,e.content.toString()),a=!1)}return a&&t.writeFileSync(n,e.fullHtml.toString()),o("success",`Report generated (${n})`),e.fullHtml}catch(e){r(e)}}async renderTestReport(){const e=await this.renderTestReportContent();if(this.getConfigValue("boilerplate")){const s=u(this.jestConfig?this.jestConfig.rootDir:"",this.getConfigValue("boilerplate")),i=t.readFileSync(s,"utf8"),n=e?e.toString():"";return{content:n,fullHtml:i.replace("{jesthtmlreporter-content}",n)}}const s=n.create({html:{}}),a=s.ele("head");a.ele("meta",{charset:"utf-8"}),a.ele("title",{},this.getConfigValue("pageTitle"));let o=i.join(__dirname,`../style/${this.getConfigValue("theme")}.css`);this.getConfigValue("styleOverridePath")&&(o=this.getConfigValue("styleOverridePath"));if(!this.getConfigValue("useCssFile")&&!this.getConfigValue("styleOverridePath")){const e=t.readFileSync(o,"utf8");a.raw(`<style type="text/css">${e}</style>`)}else a.ele("link",{rel:"stylesheet",type:"text/css",href:o});const r=s.ele("body");return e&&r.raw(e.toString()),this.getConfigValue("customScriptPath")&&r.raw(`<script src="${this.getConfigValue("customScriptPath")}"><\/script>`),{fullHtml:s.toString(),content:e?e.toString():""}}renderTestSuiteHeader(e,t){const s=e.ele("summary",{class:"suite-info"});s.ele("div",{class:"suite-path"},t.testFilePath);const i=(t.perfStats.end-t.perfStats.start)/1e3,n=["suite-time"];i>this.getConfigValue("executionTimeWarningThreshold")&&n.push("warn"),s.ele("div",{class:n.join(" ")},`${i}s`)}async renderTestReportContent(){try{if(!this.testData||0===Object.entries(this.testData).length)throw Error("No test data provided");const t=n.begin().element("main",{class:"jesthtml-content"}),s=t.ele("header");s.ele("h1",{id:"title"},this.getConfigValue("pageTitle"));const i=this.getConfigValue("logo");i&&s.ele("img",{id:"logo",src:i});const a=t.ele("section",{id:"metadata-container"});if(this.testData.startTime&&!isNaN(this.testData.startTime)){const t=new Date(this.testData.startTime);if(t){const s=e(t,this.getConfigValue("dateFormat"));a.ele("div",{id:"timestamp"},`Started: ${s}`)}}const o=a.ele("div",{id:"summary"}),r=o.ele("div",{id:"suite-summary"}),u=(e,t)=>[`summary-${e}`,t>0?"":" summary-empty"].join(" ");r.ele("div",{class:"summary-total"},`Suites (${this.testData.numTotalTestSuites})`),r.ele("div",{class:u("passed",this.testData.numPassedTestSuites)},`${this.testData.numPassedTestSuites} passed`),r.ele("div",{class:u("failed",this.testData.numFailedTestSuites)},`${this.testData.numFailedTestSuites} failed`),r.ele("div",{class:u("pending",this.testData.numPendingTestSuites)},`${this.testData.numPendingTestSuites} pending`),this.testData.snapshot&&this.testData.snapshot.unchecked>0&&this.getConfigValue("includeObsoleteSnapshots")&&r.ele("div",{class:"summary-obsolete-snapshots"},`${this.testData.snapshot.unchecked} obsolete snapshots`);const c=o.ele("div",{id:"test-summary"});c.ele("div",{class:"summary-total"},`Tests (${this.testData.numTotalTests})`),c.ele("div",{class:u("passed",this.testData.numPassedTests)},`${this.testData.numPassedTests} passed`),c.ele("div",{class:u("failed",this.testData.numFailedTests)},`${this.testData.numFailedTests} failed`),c.ele("div",{class:u("pending",this.testData.numPendingTests)},`${this.testData.numPendingTests} pending`);const d=((e,t)=>{const{sortType:s,params:i}=function(e){if(!e)return{sortType:null};const[t,s]=e.split(":").map((e=>e.trim())),i=s?.split(",").map((e=>e.trim()));if(!["status","executiondesc","executionasc","titledesc","titleasc"].includes(t.toLowerCase()))return{sortType:null};return{sortType:t.toLowerCase(),params:i}}(t);switch(s){case"status":{const t=i?.every((e=>g.includes(e)))?i:void 0;return p(e,t)}case"executiondesc":return f(e);case"executionasc":return m(e);case"titledesc":return y(e);case"titleasc":return S(e);default:return e}})(this.testData.testResults,this.getConfigValue("sort")),h=this.getConfigValue("statusIgnoreFilter");let T=[];return h&&(T=h.replace(/\s/g,"").toLowerCase().split(",")),d&&d.forEach(((e,s)=>{const i=t.ele("details",{id:`suite-${s+1}`,class:"suite-container",open:this.getConfigValue("collapseSuitesByDefault")?void 0:""});this.renderTestSuiteHeader(i,e);const n=i.ele("div",{class:"suite-tests"});if(!e.testResults||e.testResults.length<=0){if(e.failureMessage&&this.getConfigValue("includeSuiteFailure")){n.ele("div",{class:"test-result failed"}).ele("div",{class:"failureMessages suiteFailure"}," ").ele("pre",{class:"failureMsg"},l(e.failureMessage))}}else e.testResults.filter((e=>!T.includes(e.status))).forEach((async e=>{const t=n.ele("div",{class:`test-result ${e.status}`}),s=t.ele("div",{class:"test-info"});if(s.ele("div",{class:"test-suitename"},e.ancestorTitles&&e.ancestorTitles.length>0?e.ancestorTitles.join(" > "):" "),s.ele("div",{class:"test-title"},e.title),s.ele("div",{class:"test-status"},e.status),s.ele("div",{class:"test-duration"},e.duration?e.duration/1e3+"s":" "),e.failureMessages&&e.failureMessages.length>0&&this.getConfigValue("includeFailureMsg")){const s=t.ele("div",{class:"failureMessages"}," ");e.failureMessages.map((e=>this.getConfigValue("includeStackTrace")?e:e.split(/\n\s+at/)[0].trim().replace(/\n+$/,""))).forEach((e=>{s.ele("pre",{class:"failureMsg"},l(e))}))}})),this.consoleLogList&&this.consoleLogList.length>0&&this.getConfigValue("includeConsoleLog")&&this.renderSuiteConsoleLogs(e,i),e.snapshot&&e.snapshot.unchecked>0&&this.getConfigValue("includeObsoleteSnapshots")&&this.renderSuiteObsoleteSnapshots(i,e)})),t}catch(e){r(e)}}renderSuiteConsoleLogs(e,t){const s=this.consoleLogList.find((t=>t.filePath===e.testFilePath));if(s&&s.logs.length>0){const e=t.ele("div",{class:"suite-consolelog"});e.ele("div",{class:"suite-consolelog-header"},"Console Log"),s.logs.forEach((t=>{const s=e.ele("div",{class:"suite-consolelog-item"});s.ele("pre",{class:"suite-consolelog-item-origin"},l(t.origin)),s.ele("pre",{class:"suite-consolelog-item-message"},l(t.message))}))}}renderSuiteObsoleteSnapshots(e,t){const s=e.ele("div",{class:"suite-obsolete-snapshots"});s.ele("div",{class:"suite-obsolete-snapshots-header"},"Obsolete snapshots");s.ele("div",{class:"suite-obsolete-snapshots-item"}).ele("pre",{class:"suite-obsolete-snapshots-item-message"},t.snapshot.uncheckedKeys.join("\n"))}getConfigValue(e){return this.config[e]}}const b=e=>new D(e).generate();module.exports=function(e,t){const s=[];if(Object.prototype.hasOwnProperty.call(e,"testResults")){const s=e;return b({testData:s,options:t}),s}this.onTestResult=(e,t)=>{t.console&&s.push({filePath:t.testFilePath,logs:t.console})},this.onRunComplete=(i,n)=>b({testData:n,options:t,jestConfig:e,consoleLogs:s})};
{
"name": "jest-html-reporter",
"version": "3.10.2",
"version": "4.0.0",
"description": "Jest test results processor for generating a summary in HTML",

@@ -13,5 +13,6 @@ "main": "dist/index.js",

"tsc": "tsc",
"lint": "tslint --project . -e '**/*.js' -e '**/*.json'",
"lint": "eslint src/",
"jest": "jest --no-cache --config=jest.config.json",
"test": "npm run lint && npm run bundle && npm run jest",
"test": "npm run lint && npm run jest",
"test:watch": "npm run jest -- --watch --no-coverage",
"bundle": "rollup -c",

@@ -38,11 +39,12 @@ "build": "npm run test && npm run bundle"

"engines": {
"node": ">=4.8.3"
"node": ">=14.0.0"
},
"dependencies": {
"@jest/reporters": "^29.7.0",
"@jest/test-result": "^29.7.0",
"@jest/types": "^29.6.3",
"dateformat": "3.0.2",
"mkdirp": "^1.0.3",
"dateformat": "3.0.2",
"strip-ansi": "6.0.1",
"xmlbuilder": "15.0.0",
"@jest/test-result": "^29.0.2",
"@jest/types": "^29.0.2"
"xmlbuilder": "15.0.0"
},

@@ -54,22 +56,23 @@ "peerDependencies": {

"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.8.7",
"@babel/preset-typescript": "^7.8.3",
"@jest/console": "^29.0.2",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-node-resolve": "^7.1.1",
"@eslint/js": "^9.19.0",
"@jest/console": "^29.7.0",
"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@types/dateformat": "^3.0.X",
"@types/jest": "^29.0.0",
"@types/jest": "^29.5.14",
"@types/mkdirp": "1.0.2",
"@types/node": "12.20.12",
"@types/node": "^22.13.0",
"@types/sinon": "9.0.11",
"babel-jest": "^29.0.2",
"jest": "^29.0.2",
"rollup": "2.47.0",
"rollup-plugin-terser": "7.0.2",
"eslint": "^9.19.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"rollup": "^4.34.1",
"sinon": "^9.0.1",
"ts-jest": "^29.0.0",
"tslint": "^5.12.0",
"tslib": "^2.8.1",
"tslint-config-prettier": "^1.18.0",
"typescript": "^4.3.x"
"typescript": "^5.7.3",
"typescript-eslint": "^8.22.0"
},

@@ -76,0 +79,0 @@ "browserslist": [

@@ -6,9 +6,7 @@ <p align="center">

A <a href="https://github.com/facebook/jest">Jest</a> test results processor for generating a summary in HTML.
<br>
<a href="https://github.com/Hargne/jest-html-reporter/wiki"><strong>Documentation ยป</strong></a>
<br />
<br />
<img src="https://img.shields.io/npm/v/jest-html-reporter?style=flat-square">
<img src="https://img.shields.io/node/v/jest-html-reporter?style=flat-square">
<img src="https://img.shields.io/npm/dm/jest-html-reporter?style=flat-square">
<img src="https://img.shields.io/github/actions/workflow/status/Hargne/jest-html-reporter/main.yml?branch=master&style=flat-square">
<br />

@@ -56,3 +54,3 @@ <br />

There are multiple configuration options available. To read more about these, please refer to the [documentation](https://github.com/Hargne/jest-html-reporter/wiki/configuration).
There are multiple configuration options available. Read more about these further down in this document.

@@ -69,44 +67,37 @@ #### Alternative Usage as a Test Results Processor

**Note:** When running as a testResultsProcessor, the configuration needs be placed within a new file named `jesthtmlreporter.config.json` residing in the root folder.
More information about this can be found in the [documentation](https://github.com/Hargne/jest-html-reporter/wiki/configuration).
***Note:** When running as a testResultsProcessor, the configuration needs be placed within a new file named `jesthtmlreporter.config.json` residing in the root folder.*
### Node Compatibility
## ๐Ÿ“Œ Configuration Options (All Optional)
<img src="https://img.shields.io/node/v/jest-html-reporter?style=flat-square">
| Option | Type | Default | Description |
| ----------------------------------- | --------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`append`** | `boolean` | `false` | Append test results to an existing report. |
| **`boilerplate`** | `string` | `null` | Path to an HTML boilerplate file. The `{jesthtmlreporter-content}` variable will be replaced with test results. |
| **`collapseSuitesByDefault`** | `boolean` | `false` | Collapse test suites (accordions) by default. |
| **`customScriptPath`** | `string` | `null` | Path to an external script file injected into the report. |
| **`dateFormat`** | `string` | `yyyy-mm-dd HH:MM:ss` | Date format for timestamps. See [documentation](https://github.com/Hargne/jest-html-reporter/wiki/Date-Format) for available formats. |
| **`executionTimeWarningThreshold`** | `number` | `5` | Warn if a test suite exceeds this execution time (in seconds). |
| **`includeConsoleLog`** | `boolean` | `false` | Include `console.log` outputs in the report (**requires** `--verbose=false`). |
| **`includeFailureMsg`** | `boolean` | `false` | Show detailed error messages for failed tests. |
| **`includeStackTrace`** | `boolean` | `true` | Show stack traces for failed tests. |
| **`includeSuiteFailure`** | `boolean` | `false` | Show detailed errors for entire failed test suites. |
| **`includeObsoleteSnapshots`** | `boolean` | `false` | Show obsolete snapshot names. |
| **`logo`** | `string` | `null` | Path to an image file to display in the report header. |
| **`outputPath`** | `string` | `./test-report.html` | Full path for the output report file (**must end in `.html`**). |
| **`pageTitle`** | `string` | `"Test Report"` | Title of the document and top-level heading. |
| **`sort`** | `string` | `null` | Sort test results by a specific method. Available values:<br> โžค **`status`** โ†’ Sorts by test status (**pending โ†’ failed โ†’ passed**).<br> โžค **`status:{custom-order}`** โ†’ Custom status order (e.g., `"status:failed,passed,pending"`).<br> โžค **`executionasc`** โ†’ Sorts by execution time **ascending**.<br> โžค **`executiondesc`** โ†’ Sorts by execution time **descending**.<br> โžค **`titleasc`** โ†’ Sorts by suite filename/test name **ascending**.<br> โžค **`titledesc`** โ†’ Sorts by suite filename/test name **descending**. |
| **`statusIgnoreFilter`** | `string` | `null` | **Comma-separated** list of statuses to exclude: `"passed"`, `"pending"`, `"failed"`. |
| **`styleOverridePath`** | `string` | `null` | Path to a CSS file to override default styles. |
| **`useCssFile`** | `boolean` | `false` | Link to the CSS file instead of inlining styles. |
This plugin is compatible with Node version `^4.8.3`
## Continuous Integration
## Configuration
All the configuration options provided in the table above are available via environment variables and follows the pattern of snake case in uppercase prepended with `JEST_HTML_REPORTER_`
Please note that all configuration properties are optional.
**Example:** `customScriptPath` -> `JEST_HTML_REPORTER_CUSTOM_SCRIPT_PATH`
| Property | Type | Description | Default |
| ------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `append` | `BOOLEAN` | If set to true, new test results will be appended to the existing test report | `false` |
| `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` |
| `collapseSuitesByDefault` | `BOOLEAN` | Whether to collapse test suites by default or not | `false` |
| `customScriptPath` | `STRING` | Path to a javascript file that should be injected into the test report | `null` |
| `dateFormat` | `STRING` | The format in which date/time should be formatted in the test report. Have a look in the [documentation](https://github.com/Hargne/jest-html-reporter/wiki/Date-Format) for the available date format variables. | `"yyyy-mm-dd HH:MM:ss"` |
| `executionTimeWarningThreshold` | `NUMBER` | The threshold for test execution time (in seconds) in each test suite that will render a warning on the report page. 5 seconds is the default timeout in Jest. | `5` |
| `includeConsoleLog` | `BOOLEAN` | If set to true, this will output all triggered console logs for each test suite. Please note that you have to run Jest together with `--verbose=false` in order to have Jest catch any logs during the tests. | `false` |
| `includeFailureMsg` | `BOOLEAN` | If this setting is set to true, this will output the detailed failure message for each failed test. | `false` |
| `includeStackTrace` | `BOOLEAN` | Turning this option off will cut the stack trace from the failure messages. | `true` |
| `includeSuiteFailure` | `BOOLEAN` | If set to true, this will output the detailed failure message for complete suite failures. | `false` |
| `includeObsoleteSnapshots` | `BOOLEAN` | If set to true, this will output obsolete snapshot names. | `false` |
| `logo` | `STRING` | Path to a logo that will be included in the header of the report | `null` |
| `outputPath` | `STRING` | The path to where the plugin will output the HTML report. The path must include the filename and end with .html | `"./test-report.html"` |
| `pageTitle` | `STRING` | The title of the document. This string will also be outputted on the top of the page. | `"Test Suite"` |
| `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` |
| `styleOverridePath` | `STRING` | The path to a file containing CSS styles that should override the default styling.\* | `null` |
| `useCssFile` | `BOOLEAN` | If set to true, the CSS styles will link in the current theme's .css file instead of inlining its content on the page | `false` |
***NOTE:** Environment variables will take precedence over configurations set in jesthtmlreporter.config.json and package.json*
> *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).
### CI Example
## Continuous Integration
Configuration may also be performed with environment variables for dynamic file saving paths in different environments. **\*NOTE:** Environment variables will take precedence over configurations set in jesthtmlreporter.config.json and package.json\*
#### Example
Here is an example of dynamically naming your output file and test report title to match your current branch that one might see in a automated deployment pipeline before running their tests.

@@ -119,5 +110,1 @@

```
#### Configuration Environment Variables
The environment variables reflect the configuration options available in JSON format. Please read the [documentation](https://github.com/Hargne/jest-html-reporter/wiki/configuration#configuration-environment-variables) for more information on these variables.

Sorry, the diff of this file is not supported yet