diff --git a/spec/unit/default-display.spec.ts b/spec/unit/default-display.spec.ts index 14381e5e..ec2e29b5 100644 --- a/spec/unit/default-display.spec.ts +++ b/spec/unit/default-display.spec.ts @@ -457,6 +457,49 @@ describe("with default display", () => { ); }); + it("should report ERRORS when afterAll in suite throws", done => { + JasmineEnv.execute( + this.reporter, + env => { + env.describe("suite", () => { + env.it("spec", () => { + env.passed(); + }); + env.afterAll(() => { + throw new Error("afterAll threw"); + }); + }); + }, + (outputs, summary) => { + expect(summary).toContain("Executed 1 of 1 spec (1 ERROR) in {time}."); + done(); + } + ); + }); + + it("should report ERRORS when afterAll throws", done => { + JasmineEnv.execute( + this.reporter, + env => { + env.describe("suite", () => { + env.it("spec", () => { + env.passed(); + }); + env.afterAll(() => { + throw new Error("afterAll in suite threw"); + }); + }); + env.afterAll(() => { + throw new Error("afterAll threw"); + }); + }, + (outputs, summary) => { + expect(summary).toContain("Executed 1 of 1 spec (2 ERRORS) in {time}."); + done(); + } + ); + }); + it("should report skipped with failure and pending", done => { JasmineEnv.execute( this.reporter, diff --git a/spec/unit/display-processor.spec.ts b/spec/unit/display-processor.spec.ts index d815376c..fa05ff00 100644 --- a/spec/unit/display-processor.spec.ts +++ b/spec/unit/display-processor.spec.ts @@ -139,6 +139,50 @@ describe("spec reporter", () => { }); }); + describe("when suite done", () => { + it("should report errors in afterAll", done => { + JasmineEnv.execute( + this.reporter, + env => { + env.describe("suite", () => { + env.it("passing spec", () => { + env.passed(); + }); + env.afterAll(() => { + throw new Error("throw in afterAll in suite"); + }); + }); + }, + outputs => { + expect(outputs).contains(/throw in afterAll/); + done(); + } + ); + }); + }); + + describe("when jasmine done", () => { + it("should report errors in afterAll", done => { + JasmineEnv.execute( + this.reporter, + env => { + env.describe("suite", () => { + env.it("passing spec", () => { + env.passed(); + }); + }); + env.afterAll(() => { + throw new Error("throw in afterAll"); + }); + }, + outputs => { + expect(outputs).contains(/throw in afterAll/); + done(); + } + ); + }); + }); + describe("when summary", () => { it("should display summary error messages", done => { JasmineEnv.execute( diff --git a/src/display/execution-display.ts b/src/display/execution-display.ts index c1d32c70..1e199023 100644 --- a/src/display/execution-display.ts +++ b/src/display/execution-display.ts @@ -98,7 +98,10 @@ export class ExecutionDisplay { this.suiteHierarchy.push(result); } - public suiteDone(): void { + public suiteDone(result: CustomReporterResult): void { + if (result && result.failedExpectations && result.failedExpectations.length) { + this.failed(result); + } const suite: CustomReporterResult = this.suiteHierarchy.pop(); if (this.suiteHierarchyDisplayed[this.suiteHierarchyDisplayed.length - 1] === suite) { this.suiteHierarchyDisplayed.pop(); diff --git a/src/display/summary-display.ts b/src/display/summary-display.ts index 7b9c5571..af0b5d61 100644 --- a/src/display/summary-display.ts +++ b/src/display/summary-display.ts @@ -12,13 +12,15 @@ export class SummaryDisplay { const pluralizedSpec = (metrics.totalSpecsDefined === 1 ? " spec" : " specs"); const execution = `Executed ${metrics.executedSpecs} of ${metrics.totalSpecsDefined}${pluralizedSpec}`; let status = ""; - if (metrics.failedSpecs === 0) { + if (metrics.failedSpecs === 0 && metrics.errors.length === 0) { status = (metrics.totalSpecsDefined === metrics.executedSpecs) ? " SUCCESS".successful : " INCOMPLETE".pending; } const failed = (metrics.failedSpecs > 0) ? ` (${metrics.failedSpecs} FAILED)` : ""; const pending = (metrics.pendingSpecs > 0) ? ` (${metrics.pendingSpecs} PENDING)` : ""; const skipped = (metrics.skippedSpecs > 0) ? ` (${metrics.skippedSpecs} SKIPPED)` : ""; + let errors = (metrics.errors.length > 1) ? ` (${metrics.errors.length} ERRORS)` : ""; + errors = (metrics.errors.length === 1) ? ` (${metrics.errors.length} ERROR)` : errors; const duration = this.configuration.summary.displayDuration ? ` in ${metrics.duration}` : ""; this.logger.resetIndent(); @@ -29,10 +31,14 @@ export class SummaryDisplay { if (this.configuration.summary.displayFailed && metrics.failedSpecs > 0) { this.failuresSummary(); } + if (this.configuration.summary.displayFailed && metrics.errors.length > 0) { + this.errorsSummary(metrics.errors); + } if (this.configuration.summary.displayPending && metrics.pendingSpecs > 0) { this.pendingsSummary(); } - this.logger.log(execution + status + failed.failed + pending.pending + skipped.pending + duration + "."); + this.logger.log(execution + status + errors.failed + failed.failed + + pending.pending + skipped.pending + duration + "."); if (metrics.random) { this.logger.log(`Randomized with seed ${metrics.seed}.`); @@ -103,4 +109,32 @@ export class SummaryDisplay { this.logger.log(pendingReason.pending); this.logger.resetIndent(); } + + private errorsSummary(errors: CustomReporterResult[]): void { + this.logger.log("**************************************************"); + this.logger.log("* Errors *"); + this.logger.log("**************************************************"); + this.logger.newLine(); + for (let i = 0; i < errors.length; i++) { + this.errorSummary(errors[i], i + 1); + this.logger.newLine(); + } + this.logger.newLine(); + this.logger.resetIndent(); + } + + private errorSummary(error: CustomReporterResult, index: number): void { + this.logger.log(`${index}) ${error.fullName}`); + if (this.configuration.summary.displayErrorMessages) { + this.logger.increaseIndent(); + this.logger.process( + error, + (displayProcessor: DisplayProcessor, object: CustomReporterResult, log: string) => { + return displayProcessor.displaySummaryErrorMessages(object, log); + } + ); + this.logger.decreaseIndent(); + } + } + } diff --git a/src/execution-metrics.ts b/src/execution-metrics.ts index 98ee116f..db69e76b 100644 --- a/src/execution-metrics.ts +++ b/src/execution-metrics.ts @@ -14,6 +14,7 @@ export class ExecutionMetrics { public skippedSpecs = 0; public totalSpecsDefined = 0; public executedSpecs = 0; + public errors: CustomReporterResult[] = []; public duration: string; public random = false; public seed: string; diff --git a/src/spec-reporter.ts b/src/spec-reporter.ts index f6ac317e..b2a6ccc1 100644 --- a/src/spec-reporter.ts +++ b/src/spec-reporter.ts @@ -78,6 +78,11 @@ export class SpecReporter implements CustomReporter { public jasmineDone(runDetails: RunDetails): void { this.metrics.stop(runDetails); + if (runDetails.failedExpectations.length) { + const error = this.runDetailsToResult(runDetails); + this.metrics.errors.push(error); + this.display.failed(error); + } this.summary.display(this.metrics); } @@ -86,7 +91,10 @@ export class SpecReporter implements CustomReporter { } public suiteDone(result: CustomReporterResult): void { - this.display.suiteDone(); + this.display.suiteDone(result); + if (result.failedExpectations.length) { + this.metrics.errors.push(result); + } } public specStarted(result: CustomReporterResult): void { @@ -107,4 +115,23 @@ export class SpecReporter implements CustomReporter { this.display.failed(result); } } + + private runDetailsToResult(runDetails: RunDetails): CustomReporterResult { + return { + description: "Non-spec failure", + failedExpectations: runDetails.failedExpectations.map(expectation => { + return { + actual: "", + expected: "", + matcherName: "", + message: expectation.message, + passed: false, + stack: (expectation as any).stack, + }; + }), + fullName: "Non-spec failure", + id: "Non-spec failure", + }; + } + }