diff --git a/src/lib/FunctionAssertion.ts b/src/lib/FunctionAssertion.ts index 9a441a30..22d855c5 100644 --- a/src/lib/FunctionAssertion.ts +++ b/src/lib/FunctionAssertion.ts @@ -1,4 +1,5 @@ import { AssertionError } from "assert"; +import { isDeepStrictEqual } from "util"; import { Assertion, Constructor } from "./Assertion"; import { ErrorAssertion } from "./ErrorAssertion"; @@ -29,25 +30,41 @@ export class FunctionAssertion extends Assertion { } /** - * Check if the function throws anything when called. + * Check if the function throws when called. Optionally, you can check that + * the thrown error is strictly equal to an `Error` instance by passing it as + * a parameter. * + * @param error the error the function should throw * @returns the assertion instance */ - public toThrow(): this { + public toThrow(error?: E): this { const captured = this.captureError(); - const error = new AssertionError({ - actual: captured, - message: "Expected the function to throw when called" - }); - const invertedError = new AssertionError({ - actual: captured, - message: "Expected the function NOT to throw when called" - }); + + if (error !== undefined) { + return this.execute({ + assertWhen: isDeepStrictEqual(captured, error), + error: new AssertionError({ + actual: captured, + expected: error, + message: `Expected the function to throw - ${error}` + }), + invertedError: new AssertionError({ + actual: this.actual, + message: `Expected the function NOT to throw - ${error}` + }) + }); + } return this.execute({ assertWhen: captured !== NoThrow, - error, - invertedError + error: new AssertionError({ + actual: captured, + message: "Expected the function to throw when called" + }), + invertedError: new AssertionError({ + actual: captured, + message: "Expected the function NOT to throw when called" + }) }); } diff --git a/test/lib/FunctionAssertion.test.ts b/test/lib/FunctionAssertion.test.ts index e60992dd..0051e2a6 100644 --- a/test/lib/FunctionAssertion.test.ts +++ b/test/lib/FunctionAssertion.test.ts @@ -19,40 +19,86 @@ class CustomError extends Error { describe("[Unit] FunctionAssertion.test.ts", () => { describe(".toThrow", () => { - context("when the function throws", () => { - const variants = [ - -1, - "foo", - true, - null, - Error(), - new CustomError("bar") - ] as const; - - variants.forEach(error => { - it(`[${error}] returns the assertion instance`, () => { - const test = new FunctionAssertion(() => { - throw error; + context("when the error param is not present", () => { + context("and the function throws", () => { + const variants = [ + -1, + "foo", + true, + null, + Error(), + new CustomError("bar") + ] as const; + + variants.forEach(error => { + it(`[${error}] returns the assertion instance`, () => { + const test = new FunctionAssertion(() => { + throw error; + }); + + assert.deepStrictEqual(test.toThrow(), test); + assert.throws(() => test.not.toThrow(), { + message: "Expected the function NOT to throw when called", + name: AssertionError.name + }); }); + }); + }); + + context("and the function does not throw", () => { + it("throws an assertion error", () => { + const test = new FunctionAssertion(() => undefined); - assert.deepStrictEqual(test.toThrow(), test); - assert.throws(() => test.not.toThrow(), { - message: "Expected the function NOT to throw when called", + assert.throws(() => test.toThrow(), { + message: "Expected the function to throw when called", name: AssertionError.name }); + assert.deepStrictEqual(test.not.toThrow(), test); }); }); }); - context("when the function does not throw", () => { - it("throws an assertion error", () => { - const test = new FunctionAssertion(() => undefined); + context("when the error param is present", () => { + context("and the function throws", () => { + context("and the thrown error is strictly equal to the param", () => { + it("returns the assertion instance", () => { + const test = new FunctionAssertion(() => { + throw new Error("This is expected!"); + }); - assert.throws(() => test.toThrow(), { - message: "Expected the function to throw when called", - name: AssertionError.name + assert.deepStrictEqual(test.toThrow(new Error("This is expected!")), test); + assert.throws(() => test.not.toThrow(new Error("This is expected!")), { + message: "Expected the function NOT to throw - Error: This is expected!", + name: AssertionError.name + }); + }); + }); + + context("and the error is not strictly equal to the param", () => { + it("throws and assertion error", () => { + const test = new FunctionAssertion(() => { + throw new Error("This is expected!"); + }); + + assert.throws(() => test.toThrow(new Error("Another error here!")), { + message: "Expected the function to throw - Error: Another error here!", + name: AssertionError.name + }); + assert.deepStrictEqual(test.not.toThrow(new Error("Another error here!")), test); + }); + }); + }); + + context("and the function does not throw", () => { + it("throw an assertion error", () => { + const test = new FunctionAssertion(() => undefined); + + assert.throws(() => test.toThrow(new Error("Unreachable!")), { + message: "Expected the function to throw - Error: Unreachable!", + name: AssertionError.name + }); + assert.deepStrictEqual(test.not.toThrow(new Error("Unreachable!")), test); }); - assert.deepStrictEqual(test.not.toThrow(), test); }); }); });