How to test the type of a thrown exception in Jest

后端 未结 12 1210
误落风尘
误落风尘 2020-12-04 18:37

I\'m working with some code where I need to test the type of an exception thrown by a function (is it TypeError, ReferenceError, etc.?).

My current testing framework

相关标签:
12条回答
  • 2020-12-04 19:03

    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 documentation.

    0 讨论(0)
  • 2020-12-04 19:05

    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);
    });
    
    0 讨论(0)
  • 2020-12-04 19:06

    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 of a specific type:

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

    Or an error is thrown with a specific message:

    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.

    A 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.

    0 讨论(0)
  • 2020-12-04 19:06

    Modern Jest allows you to make more checks on a 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,
      }
    
    0 讨论(0)
  • 2020-12-04 19:06

    Further to Peter Danis' post, I 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 it should make the testing run successfully.

    0 讨论(0)
  • 2020-12-04 19:09

    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)
        }
      }
    
    0 讨论(0)
提交回复
热议问题