From ba9d042e7a661b445f8751eb6c38a628c35ca759 Mon Sep 17 00:00:00 2001 From: JoseLion Date: Tue, 30 Aug 2022 22:37:12 -0500 Subject: [PATCH 1/2] feat(function-assertion): Add .toThrow(Error) overload Add an overload to the `.toThrow()` matcher so we can match against an error instance directly. The errors are compared to be strictly equal. --- src/lib/FunctionAssertion.ts | 41 +++++++++---- test/lib/FunctionAssertion.test.ts | 94 ++++++++++++++++++++++-------- 2 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/lib/FunctionAssertion.ts b/src/lib/FunctionAssertion.ts index 9a441a30..58c8cfd0 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 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); }); }); }); From 7de2d900587f9fe856e8a13aa86f5b7d945bb1e2 Mon Sep 17 00:00:00 2001 From: Jose Luis Leon Date: Fri, 2 Sep 2022 17:57:32 -0500 Subject: [PATCH 2/2] Address @byrpatrick comments --- src/lib/FunctionAssertion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/FunctionAssertion.ts b/src/lib/FunctionAssertion.ts index 58c8cfd0..22d855c5 100644 --- a/src/lib/FunctionAssertion.ts +++ b/src/lib/FunctionAssertion.ts @@ -31,8 +31,8 @@ export class FunctionAssertion extends Assertion { /** * Check if the function throws when called. Optionally, you can check that - * the thrown error is strictly equal an `Error` instance by passing it as a - * parameter. + * 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