Skip to content

Commit

Permalink
Feat: display pretty stacktraces (#467)
Browse files Browse the repository at this point in the history
* bootstrap implementation

* fix typo

* introduce stacktrace option

* rename processor

* allow pretty stacktrace color customization

* add pretty stacktrace test

* add StacktraceOptions to exports
  • Loading branch information
bcaudan authored Mar 22, 2020
1 parent 73d4174 commit a4a18b5
Show file tree
Hide file tree
Showing 14 changed files with 366 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ See full configuration and features: [configuration.ts](src/configuration.ts)
## Custom output
You can customize the output of the reporter yourself: [see how](docs/customize-output.md).

# Developement
# Development

## Requirements

Expand Down
5 changes: 4 additions & 1 deletion examples/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Use jasmine-spec-reporter with TypeScript
## Configuration

```typescript
import {DisplayProcessor, SpecReporter} from "jasmine-spec-reporter";
import {DisplayProcessor, SpecReporter, StacktraceOption} from "jasmine-spec-reporter";
import SuiteInfo = jasmine.SuiteInfo;

class CustomProcessor extends DisplayProcessor {
Expand All @@ -15,6 +15,9 @@ class CustomProcessor extends DisplayProcessor {

jasmine.getEnv().clearReporters();
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.NONE
},
customProcessors: [CustomProcessor],
}));
```
Expand Down
5 changes: 4 additions & 1 deletion examples/typescript/spec/helpers/reporter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {DisplayProcessor, SpecReporter} from "jasmine-spec-reporter";
import {DisplayProcessor, SpecReporter, StacktraceOption} from "jasmine-spec-reporter";
import SuiteInfo = jasmine.SuiteInfo;

class CustomProcessor extends DisplayProcessor {
Expand All @@ -9,5 +9,8 @@ class CustomProcessor extends DisplayProcessor {

jasmine.getEnv().clearReporters();
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.NONE
},
customProcessors: [CustomProcessor],
}));
13 changes: 13 additions & 0 deletions spec/helpers/test-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ let addMatchers = () => {
}
return {
pass: false,
message: `Expect\n${actual.join("\n")}\nto contains\n${sequence.join("\n")}`
};
},
};
Expand Down Expand Up @@ -90,6 +91,18 @@ const JasmineEnv = {
env.failed = () => {
env.expect(true).toBe(false);
};
env.failedWithFakeStack = () => {
env.addMatchers({
throw: () => {
return {
compare: () => {
throw new Error("oops");
}
};
}
});
env.expect().throw();
};
testFn(env);
env.addReporter(reporter);
env.addReporter({
Expand Down
8 changes: 8 additions & 0 deletions spec/unit/configuration-parser.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {StacktraceOption} from "../../built/configuration";
import * as ConfigurationParser from "../../built/configuration-parser";
import {TestProcessor} from "../helpers/test-processor";

Expand All @@ -19,4 +20,11 @@ describe("Configuration parser", () => {
it("should add custom options", () => {
expect(ConfigurationParser.parse({customOptions: {test: "foo"}}).customOptions).toEqual({test: "foo"});
});

it("should warn if outdated `displayStacktrace` boolean value is used", () => {
spyOn(console, "warn");
expect(ConfigurationParser.parse({spec: {displayStacktrace: true as any}}).spec.displayStacktrace).toEqual(StacktraceOption.NONE);
// tslint:disable-next-line:no-unbound-method
expect(console.warn).toHaveBeenCalled();
});
});
227 changes: 217 additions & 10 deletions spec/unit/display-stacktrace.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
describe("With spec display stacktrace enabled", () => {
describe("With spec display stacktrace 'raw' enabled", () => {
beforeEach(() => {
this.reporter = new global.SpecReporter({
spec: {
displayStacktrace: true
displayStacktrace: "raw"
}
});
});

describe("when failed spec", () => {
it("should display with error messages with stacktraces", done => {
it("should display with error messages with raw stacktraces", done => {
JasmineEnv.execute(
this.reporter,
env => {
Expand Down Expand Up @@ -36,7 +36,7 @@ describe("With spec display stacktrace enabled", () => {
});

describe("when summary", () => {
it("should not report stacktraces in failures summary", done => {
it("should not report raw stacktraces in failures summary", done => {
JasmineEnv.execute(
this.reporter,
env => {
Expand Down Expand Up @@ -70,17 +70,17 @@ describe("With spec display stacktrace enabled", () => {
});
});

describe("With summary display stacktrace enabled", () => {
describe("With summary display stacktrace 'raw' enabled", () => {
beforeEach(() => {
this.reporter = new global.SpecReporter({
summary: {
displayStacktrace: true
displayStacktrace: "raw"
}
});
});

describe("when failed spec", () => {
it("should not display stacktraces with error messages", done => {
it("should not display raw stacktraces with error messages", done => {
JasmineEnv.execute(
this.reporter,
env => {
Expand All @@ -100,7 +100,7 @@ describe("With summary display stacktrace enabled", () => {
});

describe("when summary", () => {
it("should report failures summary with stacktraces", done => {
it("should report failures summary with raw stacktraces", done => {
JasmineEnv.execute(
this.reporter,
env => {
Expand Down Expand Up @@ -141,19 +141,226 @@ describe("With summary display stacktrace enabled", () => {
});
});

describe("With spec display stacktrace 'pretty' enabled", () => {
beforeEach(() => {
this.reporter = new global.SpecReporter({
spec: {
displayStacktrace: "pretty"
}
});
});

describe("when failed spec", () => {
it("should display with error messages with pretty stacktraces", done => {
JasmineEnv.execute(
this.reporter,
env => {
env.describe("suite", () => {
env.it("failed spec", () => {
env.failedWithFakeStack();
});
});
},
outputs => {
expect(outputs).not.contains(/passed assertion/);
expect(outputs).contains([
" ✗ failed spec",
" - Error: oops",
"",
/test-helper.js:\d+:\d+/,
" return {",
" compare: function () {",
" throw new Error(\"oops\");",
" ~",
" }",
" };",
"",
/test-helper.js:\d+:\d+/,
" }",
" });",
" env.expect().throw();",
" ~",
" };",
" testFn(env);",
"",
/display-stacktrace.spec.js:\d+:\d+/,
" env.describe(\"suite\", function () {",
" env.it(\"failed spec\", function () {",
" env.failedWithFakeStack();",
" ~",
" });",
" });",
""
]);
done();
}
);
});
});

describe("when summary", () => {
it("should not report pretty stacktraces in failures summary", done => {
JasmineEnv.execute(
this.reporter,
env => {
env.describe("suite 1", () => {
env.it("spec 1", () => {
env.failedWithFakeStack();
});
env.describe("suite 2", () => {
env.it("spec 2", () => {
env.failedWithFakeStack();
});
});
});
},
(outputs, summary) => {
expect(summary).contains([
/.*/,
/Failures/,
/.*/,
"",
"1) suite 1 spec 1",
" - Error: oops",
"", "2) suite 1 suite 2 spec 2",
" - Error: oops",
""
]);
done();
}
);
});
});
});

describe("With summary display stacktrace 'pretty' enabled", () => {
beforeEach(() => {
this.reporter = new global.SpecReporter({
summary: {
displayStacktrace: "pretty"
}
});
});

describe("when failed spec", () => {
it("should not display pretty stacktraces with error messages", done => {
JasmineEnv.execute(
this.reporter,
env => {
env.describe("suite", () => {
env.it("failed spec", () => {
env.failedWithFakeStack();
});
});
},
outputs => {
expect(outputs).not.contains(/passed assertion/);
expect(outputs).contains([ " ✗ failed spec", " - Error: oops", "" ]);
done();
}
);
});
});

describe("when summary", () => {
it("should report failures summary with pretty stacktraces", done => {
JasmineEnv.execute(
this.reporter,
env => {
env.describe("suite 1", () => {
env.it("spec 1", () => {
env.failedWithFakeStack();
});
env.describe("suite 2", () => {
env.it("spec 2", () => {
env.failedWithFakeStack();
});
});
});
},
(outputs, summary) => {
expect(summary).contains([
/.*/,
/Failures/,
/.*/,
"",
"1) suite 1 spec 1",
" - Error: oops",
"",
/test-helper.js:\d+:\d+/,
" return {",
" compare: function () {",
" throw new Error(\"oops\");",
" ~",
" }",
" };",
"",
/test-helper.js:\d+:\d+/,
" }",
" });",
" env.expect().throw();",
" ~",
" };",
" testFn(env);",
"",
/display-stacktrace.spec.js:\d+:\d+/,
" env.describe(\"suite 1\", function () {",
" env.it(\"spec 1\", function () {",
" env.failedWithFakeStack();",
" ~",
" });",
" env.describe(\"suite 2\", function () {",
"",
"",
"2) suite 1 suite 2 spec 2",
" - Error: oops",
"",
/test-helper.js:\d+:\d+/,
" return {",
" compare: function () {",
" throw new Error(\"oops\");",
" ~",
" }",
" };",
"",
/test-helper.js:\d+:\d+/,
" }",
" });",
" env.expect().throw();",
" ~",
" };",
" testFn(env);",
"",
/display-stacktrace.spec.js:\d+:\d+/,
" env.describe(\"suite 2\", function () {",
" env.it(\"spec 2\", function () {",
" env.failedWithFakeStack();",
" ~",
" });",
" });",
"",
""
]);
done();
}
);
});
});
});

describe("With custom stacktrace filter function", () => {
beforeEach(() => {
this.reporter = new global.SpecReporter({
spec: {
displayStacktrace: true
displayStacktrace: "raw"
},
stacktrace: {
filter: stacktrace => {
return "Updated stacktrace";
}
},
summary: {
displayStacktrace: true
displayStacktrace: "raw"
},
});
});
Expand Down
Loading

0 comments on commit a4a18b5

Please sign in to comment.