Jasmine tests – expect().toThrow()

Suppose you have a service that you want to test.
And let’s also suppose that this service has a method that throws an Error under some scenario.

How would you test this?

Consider this method, which is part of a service:

testingExceptions1

If we want to test this method for validity of the param, we can use Jasmine‘s toThrow matcher:

testingExceptions2

However, this test fails. It fails because the toThrow is trying to invoke the method. Looking at the code for the toThrow matcher, we can make a number of observations:

testingExceptions-jasmine

  • The actual should be a function, to be invoked within a try/catch.
  • The expected is optional. If an exception is caught and the expected is undefined, the matcher returns true;
    If the expected is defined, it is compared to the exception caught.

So, to make this work, we should instead write this:

testingExceptions3

However, this might not work properly for our scenario.
This will cause the toThrow matcher to invoke the method with no args (i.e. param = undefined) which is OK, but our service method also throws the Error when param is equal to null or empty string and this implementation won’t allow us to test those inputs as well.

So, considering the toThrow matcher expects a function and we would like to be able to pass a real param value to the test, the solution would be an annonymous function!

testingExceptions4

Note: up until now, we set the toThrow matcher to intercept ANY Error that has been thrown, anywhere in the tested code and no matter what, if an Error was caught the test will succeed.
We did this for simplicity sake, by passing undefined as the argument to the toThrow matcher.

This is not necessarily what you would want.
Actually, more often than not, you’d want to test for a specific Error, one that your code throws.

You can easily achieve this by passing a new Error(“some specific message”) to the toThrow matcher. A quick revisit to the toThrow matcher code will show that it compares expected to exception if expected is defined.

This approach will also work well for service methods that return a Function that, when invoked might throw an Error.
The service:

testingExceptions5

 

And the test:
testingExceptions6

You might ask yourself, why would you want a service to return a Function reference…
Well, for the answer you’ll have to wait for the next post 🙂

Unfortunately, there is no Github reference this time.
Feel free to use and abuse 🙂
If you modify jsBlackBelt code, please let me know or submit a pull request for the benefit of others.

11 thoughts on “Jasmine tests – expect().toThrow()

  1. Thanks!
    This was quite helpful. Even if we are using Typescript, Angular5 and jasmine. It wasn’t a 100% copy and paste but I had to use:

    expect(() => svc.function()).toThrow();

    It worked beautifully.

    Like

  2. This is awesome! Thank you.
    Still I have on e issue with the output, still fails and the error is as next:

    ————————————————————————————————–
    Expected function to throw ‘Error: Spinner must have a ‘name’ attribute.’, but it threw Error: Spinner must have a ‘name’ attribute..
    ————————————————————————————————–

    The case is 100% same as in your example. So I was wondering why might it still fail… Any thoughts?!

    Like

  3. Works, here it is (now it validates the error message as well):
    ————————————————————————————————–
    //THE FUNCTION (part of the SpinnerComponent class)
    ngOnInit(): void {
    if (!this.name) {
    throw new Error(`Spinner must have a ‘name’ attribute.`);
    }
    this.spinnerService._register(this);
    }

    //THE TEST
    spinnerComponent.name = undefined;
    expect(function () {
    spinnerComponent.ngOnInit();
    }).toThrow(new Error(`Spinner must have a ‘name’ attribute.`));
    ————————————————————————————————–

    Like

Leave a comment