Skip to content

Commit

Permalink
feat(function-assertion): Add .toThrow(Error) overload (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoseLion authored Sep 2, 2022
1 parent 5c24139 commit a32e820
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 36 deletions.
41 changes: 29 additions & 12 deletions src/lib/FunctionAssertion.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AssertionError } from "assert";
import { isDeepStrictEqual } from "util";

import { Assertion, Constructor } from "./Assertion";
import { ErrorAssertion } from "./ErrorAssertion";
Expand Down Expand Up @@ -29,25 +30,41 @@ export class FunctionAssertion<T extends AnyFunction> extends Assertion<T> {
}

/**
* 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<E extends Error>(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"
})
});
}

Expand Down
94 changes: 70 additions & 24 deletions test/lib/FunctionAssertion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
Expand Down

0 comments on commit a32e820

Please sign in to comment.