Skip to content

Commit a32e820

Browse files
authored
feat(function-assertion): Add .toThrow(Error) overload (#65)
1 parent 5c24139 commit a32e820

File tree

2 files changed

+99
-36
lines changed

2 files changed

+99
-36
lines changed

src/lib/FunctionAssertion.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { AssertionError } from "assert";
2+
import { isDeepStrictEqual } from "util";
23

34
import { Assertion, Constructor } from "./Assertion";
45
import { ErrorAssertion } from "./ErrorAssertion";
@@ -29,25 +30,41 @@ export class FunctionAssertion<T extends AnyFunction> extends Assertion<T> {
2930
}
3031

3132
/**
32-
* Check if the function throws anything when called.
33+
* Check if the function throws when called. Optionally, you can check that
34+
* the thrown error is strictly equal to an `Error` instance by passing it as
35+
* a parameter.
3336
*
37+
* @param error the error the function should throw
3438
* @returns the assertion instance
3539
*/
36-
public toThrow(): this {
40+
public toThrow<E extends Error>(error?: E): this {
3741
const captured = this.captureError();
38-
const error = new AssertionError({
39-
actual: captured,
40-
message: "Expected the function to throw when called"
41-
});
42-
const invertedError = new AssertionError({
43-
actual: captured,
44-
message: "Expected the function NOT to throw when called"
45-
});
42+
43+
if (error !== undefined) {
44+
return this.execute({
45+
assertWhen: isDeepStrictEqual(captured, error),
46+
error: new AssertionError({
47+
actual: captured,
48+
expected: error,
49+
message: `Expected the function to throw - ${error}`
50+
}),
51+
invertedError: new AssertionError({
52+
actual: this.actual,
53+
message: `Expected the function NOT to throw - ${error}`
54+
})
55+
});
56+
}
4657

4758
return this.execute({
4859
assertWhen: captured !== NoThrow,
49-
error,
50-
invertedError
60+
error: new AssertionError({
61+
actual: captured,
62+
message: "Expected the function to throw when called"
63+
}),
64+
invertedError: new AssertionError({
65+
actual: captured,
66+
message: "Expected the function NOT to throw when called"
67+
})
5168
});
5269
}
5370

test/lib/FunctionAssertion.test.ts

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,86 @@ class CustomError extends Error {
1919

2020
describe("[Unit] FunctionAssertion.test.ts", () => {
2121
describe(".toThrow", () => {
22-
context("when the function throws", () => {
23-
const variants = [
24-
-1,
25-
"foo",
26-
true,
27-
null,
28-
Error(),
29-
new CustomError("bar")
30-
] as const;
31-
32-
variants.forEach(error => {
33-
it(`[${error}] returns the assertion instance`, () => {
34-
const test = new FunctionAssertion(() => {
35-
throw error;
22+
context("when the error param is not present", () => {
23+
context("and the function throws", () => {
24+
const variants = [
25+
-1,
26+
"foo",
27+
true,
28+
null,
29+
Error(),
30+
new CustomError("bar")
31+
] as const;
32+
33+
variants.forEach(error => {
34+
it(`[${error}] returns the assertion instance`, () => {
35+
const test = new FunctionAssertion(() => {
36+
throw error;
37+
});
38+
39+
assert.deepStrictEqual(test.toThrow(), test);
40+
assert.throws(() => test.not.toThrow(), {
41+
message: "Expected the function NOT to throw when called",
42+
name: AssertionError.name
43+
});
3644
});
45+
});
46+
});
47+
48+
context("and the function does not throw", () => {
49+
it("throws an assertion error", () => {
50+
const test = new FunctionAssertion(() => undefined);
3751

38-
assert.deepStrictEqual(test.toThrow(), test);
39-
assert.throws(() => test.not.toThrow(), {
40-
message: "Expected the function NOT to throw when called",
52+
assert.throws(() => test.toThrow(), {
53+
message: "Expected the function to throw when called",
4154
name: AssertionError.name
4255
});
56+
assert.deepStrictEqual(test.not.toThrow(), test);
4357
});
4458
});
4559
});
4660

47-
context("when the function does not throw", () => {
48-
it("throws an assertion error", () => {
49-
const test = new FunctionAssertion(() => undefined);
61+
context("when the error param is present", () => {
62+
context("and the function throws", () => {
63+
context("and the thrown error is strictly equal to the param", () => {
64+
it("returns the assertion instance", () => {
65+
const test = new FunctionAssertion(() => {
66+
throw new Error("This is expected!");
67+
});
5068

51-
assert.throws(() => test.toThrow(), {
52-
message: "Expected the function to throw when called",
53-
name: AssertionError.name
69+
assert.deepStrictEqual(test.toThrow(new Error("This is expected!")), test);
70+
assert.throws(() => test.not.toThrow(new Error("This is expected!")), {
71+
message: "Expected the function NOT to throw - Error: This is expected!",
72+
name: AssertionError.name
73+
});
74+
});
75+
});
76+
77+
context("and the error is not strictly equal to the param", () => {
78+
it("throws and assertion error", () => {
79+
const test = new FunctionAssertion(() => {
80+
throw new Error("This is expected!");
81+
});
82+
83+
assert.throws(() => test.toThrow(new Error("Another error here!")), {
84+
message: "Expected the function to throw - Error: Another error here!",
85+
name: AssertionError.name
86+
});
87+
assert.deepStrictEqual(test.not.toThrow(new Error("Another error here!")), test);
88+
});
89+
});
90+
});
91+
92+
context("and the function does not throw", () => {
93+
it("throw an assertion error", () => {
94+
const test = new FunctionAssertion(() => undefined);
95+
96+
assert.throws(() => test.toThrow(new Error("Unreachable!")), {
97+
message: "Expected the function to throw - Error: Unreachable!",
98+
name: AssertionError.name
99+
});
100+
assert.deepStrictEqual(test.not.toThrow(new Error("Unreachable!")), test);
54101
});
55-
assert.deepStrictEqual(test.not.toThrow(), test);
56102
});
57103
});
58104
});

0 commit comments

Comments
 (0)