How to test type of thrown exception in Jest

I'm working with some code where I need to test type of exception thrown by function (Is it TypeError, ReferenceError etc.).

My current testing framework is AVA and I can test it as a second argument t.throws method, like here:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  t.is(error.message, 'UNKNOWN ERROR');
});

I started rewriting my tests to Jest and couldn't find how to easily do that. Is it even possible?

Answers:

Answer

In Jest you have to pass a function into expect(function).toThrow(blank or type of error).

Example:

test("Test description", () => {
  const t = () => {
    throw new TypeError();
  };
  expect(t).toThrow(TypeError);
});

If you need to test an existing function whether it throws with a set of arguments, you have to wrap it inside an anonymous function in expect().

Example:

test("Test description", () => {
  expect(() => {http.get(yourUrl, yourCallbackFn)}).toThrow(TypeError);
});
Answer

Little bit weird, but works and imho is good readable:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', () => {
  try {
      throwError();
      // Fail test if above expression doesn't throw anything.
      expect(true).toBe(false);
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});

Catch block catch your exception, then you can test on your raised Error. Strange expect(true).toBe(false); is needed to fail your test if expected Error will be not thrown. Otherwise, this line is never reachable (Error should be raised before them).

EDIT: @Kenny Body suggests a better solution which improve a code quality if you use expect.assertions()

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', () => {
  expect.assertions(1);
  try {
      throwError();
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});

See the original answer with more explanations: How to test type of thrown exception in Jest

Answer

I use a slightly more concise version:

expect(() => {
  //code block that should throw error
}).toThrow(TypeError) //or .toThrow('expectedErrorMessage')
Answer

From my (albeit limited) exposure to Jest, I have found that expect().toThrow() is suitable if you want to ONLY test an error is thrown with a specific message:

expect(() => functionUnderTest()).toThrow(TypeError);

OR an error is thrown of a specific type:

expect(() => functionUnderTest()).toThrow('Something bad happened!');

If you try to do both, you will get a false positive. For example if your code throws RangeError('Something bad happened!'), this test will pass:

expect(() => functionUnderTest()).toThrow(new TypeError('Something bad happened!'));

The answer by bodolsog which suggests using a try/catch is close, but rather than expecting true to be false to ensure the expect assertions in the catch are hit, you can instead use expect.assertions(2) at the start of your test where 2 is the number of expected assertions. I feel this more accurately describes the intention of the test.

Full example of testing the type AND message of an error:

describe('functionUnderTest', () => {
    it('should throw a specific type of error.', () => {
        expect.assertions(2);

        try {
            functionUnderTest();
        } catch (error) {
            expect(error).toBeInstanceOf(TypeError);
            expect(error).toHaveProperty('message', 'Something bad happened!');
        }
    }); 
});

If functionUnderTest() does NOT throw an error, the assertions will be be hit but the expect.assertions(2) will fail and the test will fail.

Answer

Haven't tried it myself but I would suggest using Jest's toThrow assertion. So I guess your example would look something like this:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  expect(t).toThrowError('UNKNOWN ERROR');
  //or
  expect(t).toThrowError(TypeError);
});

Again, haven't test it but I think it should work.

Let me know if this helped.

Happy coding!

Answer

Jest has a method toThrow(error) to test that a function throws when it is called.

So, in your case you should call it so:

expect(t).toThrowError(TypeError);

The docs

Answer

Modern jest allows you to make more checks on rejected value. For example:

const request = Promise.reject({statusCode: 404})
await expect(request).rejects.toMatchObject({ statusCode: 500 });

will fail with error

Error: expect(received).rejects.toMatchObject(expected)

- Expected
+ Received

  Object {
-   "statusCode": 500,
+   "statusCode": 404,
  }
Answer

The documentation is clear on how to do this. Let's say I have a function that takes two parameters and it will throw an error if one of them is null.

function concatStr(str1, str2) {
  const isStr1 = str1 === null
  const isStr2 = str2 === null
  if(isStr1 || isStr2) {
    throw "Parameters can't be null"
  }
  ... // continue your code

Your test

describe("errors", () => {
  it("should error if any is null", () => {
    // notice that the expect has a function that returns the function under test
    expect(() => concatStr(null, "test")).toThrow()
  })
})
Answer

I ended up writing a convenience method for our test-utils library

/**
 *  Utility method to test for a specific error class and message in Jest
 * @param {fn, expectedErrorClass, expectedErrorMessage }
 * @example   failTest({
      fn: () => {
        return new MyObject({
          param: 'stuff'
        })
      },
      expectedErrorClass: MyError,
      expectedErrorMessage: 'stuff not yet implemented'
    })
 */
  failTest: ({ fn, expectedErrorClass, expectedErrorMessage }) => {
    try {
      fn()
      expect(true).toBeFalsy()
    } catch (err) {
      let isExpectedErr = err instanceof expectedErrorClass
      expect(isExpectedErr).toBeTruthy()
      expect(err.message).toBe(expectedErrorMessage)
    }
  }
Answer

try
expect(t).rejects.toThrow()

Answer

In case you are working with Promises:

await expect(Promise.reject(new HttpException('Error message', 402)))
.rejects.toThrowError(HttpException);
Answer

Further to Peter Danis' post just wanted to emphasize the part of his solution involving "[passing] a function into expect(function).toThrow(blank or type of error)".

In Jest, when you test for a case where an error should be thrown, within your expect() wrapping of the function under testing you need to provide one additional arrow function wrapping layer in order for it to work. I.e.

Wrong (but most people's logical approach):

expect(functionUnderTesting();).toThrow(ErrorTypeOrErrorMessage);

Right:

expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);

It's very strange but should make the testing run successfully.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.