diff --git a/README.md b/README.md index d625aee..8a08c98 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ Please note that all configuration properties are optional. | `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` | diff --git a/jest.config.json b/jest.config.json index 72da33b..3cad150 100644 --- a/jest.config.json +++ b/jest.config.json @@ -28,7 +28,7 @@ "statements": 50 } }, - "verbose": false, + "verbose": true, "reporters": [ "default", [ diff --git a/src/htmlreporter.ts b/src/htmlreporter.ts index c35dbc7..6ab95fb 100644 --- a/src/htmlreporter.ts +++ b/src/htmlreporter.ts @@ -97,7 +97,7 @@ class HTMLReporter { // Decide whether to inline the CSS or not const inlineCSS: boolean = !this.getConfigValue("useCssFile") && - !!!this.getConfigValue("styleOverridePath"); + !this.getConfigValue("styleOverridePath"); if (inlineCSS) { const stylesheetContent = fs.readFileSync(stylesheetFilePath, "utf8"); @@ -116,7 +116,7 @@ class HTMLReporter { reportBody.raw(reportContent.toString()); } // Add any given custom script to the end of the body - if (!!this.getConfigValue("customScriptPath")) { + if (this.getConfigValue("customScriptPath")) { reportBody.raw( `` ); @@ -404,13 +404,22 @@ class HTMLReporter { }, " " ); - test.failureMessages.forEach((failureMsg) => { - failureMsgDiv.ele( - "pre", - { class: "failureMsg" }, - this.sanitizeOutput(failureMsg) - ); - }); + test.failureMessages + .map((failureMsg) => + !this.getConfigValue("includeStackTrace") + ? failureMsg + .split(/\n\s+at/)[0] + .trim() + .replace(/\n+$/, "") + : failureMsg + ) + .forEach((failureMsg) => { + failureMsgDiv.ele( + "pre", + { class: "failureMsg" }, + this.sanitizeOutput(failureMsg) + ); + }); } }); @@ -517,6 +526,7 @@ class HTMLReporter { logo, includeConsoleLog, includeFailureMsg, + includeStackTrace, includeSuiteFailure, includeObsoleteSnapshots, outputPath, @@ -565,6 +575,11 @@ class HTMLReporter { environmentVariable: "JEST_HTML_REPORTER_INCLUDE_FAILURE_MSG", configValue: includeFailureMsg, }, + includeStackTrace: { + defaultValue: true, + environmentVariable: "JEST_HTML_REPORTER_INCLUDE_STACK_TRACE", + configValue: includeStackTrace, + }, includeSuiteFailure: { defaultValue: false, environmentVariable: "JEST_HTML_REPORTER_INCLUDE_SUITE_FAILURE", @@ -625,7 +640,7 @@ class HTMLReporter { if (jesthtmlreporterconfig) { const parsedConfig = JSON.parse(jesthtmlreporterconfig); for (const key of Object.keys(parsedConfig)) { - if (this.config[key as keyof IJestHTMLReporterConfig]) { + if (key in this.config) { this.config[key as keyof IJestHTMLReporterConfig].configValue = parsedConfig[key]; } @@ -644,7 +659,7 @@ class HTMLReporter { if (packageJson) { const parsedConfig = JSON.parse(packageJson)["jest-html-reporter"]; for (const key of Object.keys(parsedConfig)) { - if (this.config[key as keyof IJestHTMLReporterConfig]) { + if (key in this.config) { this.config[key as keyof IJestHTMLReporterConfig].configValue = parsedConfig[key]; } @@ -669,7 +684,7 @@ class HTMLReporter { if (process.env[option.environmentVariable]) { return process.env[option.environmentVariable]; } - return option.configValue || option.defaultValue; + return option.configValue ?? option.defaultValue; } /** diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 48a1113..02ddf44 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -17,6 +17,7 @@ export type IJestHTMLReporterConfigOptions = { executionTimeWarningThreshold?: number; includeConsoleLog?: boolean; includeFailureMsg?: boolean; + includeStackTrace?: boolean; includeSuiteFailure?: boolean; includeObsoleteSnapshots?: boolean; logo?: string; @@ -35,53 +36,11 @@ export interface IJestHTMLReporterConfigOption { defaultValue: T; } -export interface IJestHTMLReporterConfig { - append: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["append"] +export type IJestHTMLReporterConfig = { + [key in keyof IJestHTMLReporterConfigOptions]: IJestHTMLReporterConfigOption< + IJestHTMLReporterConfigOptions[key] >; - boilerplate: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["boilerplate"] - >; - customScriptPath: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["customScriptPath"] - >; - dateFormat: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["dateFormat"] - >; - executionTimeWarningThreshold: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["executionTimeWarningThreshold"] - >; - includeConsoleLog: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["includeConsoleLog"] - >; - includeFailureMsg: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["includeFailureMsg"] - >; - includeSuiteFailure: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["includeSuiteFailure"] - >; - includeObsoleteSnapshots: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["includeObsoleteSnapshots"] - >; - logo: IJestHTMLReporterConfigOption; - outputPath: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["outputPath"] - >; - pageTitle: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["pageTitle"] - >; - sort: IJestHTMLReporterConfigOption; - statusIgnoreFilter: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["statusIgnoreFilter"] - >; - styleOverridePath: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["styleOverridePath"] - >; - theme: IJestHTMLReporterConfigOption; - useCssFile: IJestHTMLReporterConfigOption< - IJestHTMLReporterConfigOptions["useCssFile"] - >; -} +}; export interface IJestHTMLReporterConsole { filePath: string; diff --git a/test/htmlreporter.spec.ts b/test/htmlreporter.spec.ts index e06b970..aa39fd6 100644 --- a/test/htmlreporter.spec.ts +++ b/test/htmlreporter.spec.ts @@ -182,6 +182,54 @@ describe("HTMLReporter", () => { }); }); + describe("includeStackTrace", () => { + it("should remove stack traces in failure messages if set to false", async () => { + const reporter = new HTMLReporter({ + testData: mockedJestResponseSingleTestResult, + options: { + includeFailureMsg: true, + includeStackTrace: false, + }, + }); + const reportContent = await reporter.renderTestReportContent(); + expect(reportContent).toBeDefined(); + expect( + reportContent! + .toString() + .indexOf( + '
Error: failures that happened
' + ) + ).not.toBe(-1); + }); + it("should keep stack trace in failure messages if set to true", async () => { + const reporter = new HTMLReporter({ + testData: mockedJestResponseSingleTestResult, + options: { + includeFailureMsg: true, + includeStackTrace: true, + }, + }); + const reportContent = await reporter.renderTestReportContent(); + expect(reportContent).toBeDefined(); + expect( + reportContent!.toString().indexOf("at stack trace") + ).toBeGreaterThan(-1); + }); + it("should keep stack trace in failure messages if undefined", async () => { + const reporter = new HTMLReporter({ + testData: mockedJestResponseSingleTestResult, + options: { + includeFailureMsg: true, + }, + }); + const reportContent = await reporter.renderTestReportContent(); + expect(reportContent).toBeDefined(); + expect( + reportContent!.toString().indexOf("at stack trace") + ).toBeGreaterThan(-1); + }); + }); + describe("includeSuiteFailure", () => { it("should include suite failure message", async () => { const reporter = new HTMLReporter({ diff --git a/test/index.spec.ts b/test/index.spec.ts index 4fc776f..45cd0c1 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -3,7 +3,6 @@ import sinon, { SinonStub } from "sinon"; import JestHTMLReporter from "../src"; import { - mockedFullReportOutput, mockedJestGlobalConfig, mockedJestResponseSingleTestResult, } from "./mockdata"; @@ -12,7 +11,9 @@ describe("index", () => { let writeFileSync: SinonStub; beforeEach(() => { - writeFileSync = sinon.stub(fs, "writeFileSync").returns(null as void); + writeFileSync = sinon + .stub(fs, "writeFileSync") + .returns(null as unknown as void); }); afterEach(() => { writeFileSync.restore(); diff --git a/test/mockdata/index.ts b/test/mockdata/index.ts index 015ee31..06ccab8 100644 --- a/test/mockdata/index.ts +++ b/test/mockdata/index.ts @@ -99,7 +99,9 @@ export const mockedJestResponseSingleTestResult: AggregatedResult = { title: "title", status: "pending", ancestorTitles: ["ancestor"], - failureMessages: ["failure"], + failureMessages: [ + "Error: failures that happened\n" + "\n" + " at stack trace", + ], failureDetails: ["detailed failure"], numPassingAsserts: 0, fullName: "pending", @@ -215,7 +217,9 @@ export const mockedJestResponseMultipleTestResult: AggregatedResult = { title: "title c", status: "failed", ancestorTitles: ["ancestor c", "ancestor child"], - failureMessages: ["failure"], + failureMessages: [ + "Error: failures that happened\n" + "\n" + " at stack trace", + ], failureDetails: ["detailed failure"], numPassingAsserts: 0, fullName: "failed", @@ -279,7 +283,9 @@ export const mockedJestResponseMultipleTestResult: AggregatedResult = { title: "title c", status: "failed", ancestorTitles: ["ancestor c"], - failureMessages: ["failure"], + failureMessages: [ + "Error: failures that happened\n" + "\n" + " at stack trace", + ], failureDetails: ["detailed failure"], numPassingAsserts: 0, fullName: "failed",