9

I’m writing a test to assert that a component throws an error if provided one prop but not another.

The test itself passes, but the console still complains about an uncaught error and prints the entire stack trace. Is there a way I can get Jest to stop printing this information, as it pollutes the test runner and makes it look like something has failed.

For reference, this is my test:

it("throws an error if showCancel is set to true, but no onCancel method is provided", () => {
    // Assert that an error is thrown
    expect(() => mount(<DropTarget showCancel={ true }/>)).toThrowError("If `showCancel` is true, you must provide an `onCancel` method");
});

The error itself is thrown here:

if(props.showCancel && !props.onCancel) {
    throw new Error("If `showCancel` is true, you must provide an `onCancel` method");
}
skyboyer
  • 22,209
  • 7
  • 57
  • 64
Jordan Garvey
  • 345
  • 5
  • 16
  • I believe in your toThrowError you need to preface the string with new Error(‘string’) – Tenza Feb 18 '19 at 16:47
  • `toThrow` and `toThrowError` don’t accept an `Error` as an argument. – Jordan Garvey Feb 18 '19 at 16:50
  • 1
    I would take a look at these docs here if you haven’t already: https://jestjs.io/docs/en/expect.html#tothrowerror – Tenza Feb 18 '19 at 16:57
  • Ah so they do accept an `Error`; Visual Studio told me otherwise, thanks for linking that. Unfortunately though no luck. The test is still passing, but is still printing the stack trace of the error in the console. – Jordan Garvey Feb 18 '19 at 17:04

3 Answers3

7

I found the one line answer to my issue here.

Adding spyOn(console, "error"); (in the test that expects an error) suppresses the error from being logged.

Hristo
  • 45,559
  • 65
  • 163
  • 230
Jordan Garvey
  • 345
  • 5
  • 16
2

You can remove the console.error implementation temporarily when asserting the error and restore it back after you finish.

function toThrowSilently(fn: Function) {
  jest.spyOn(console, "error")
  console.error.mockImplementation(() => {})
  expect(fn).toThrow()
  console.error.mockRestore()
}

test('should throw', async () => {
  const app = () => throw new Error()
  toThrowSilently(app)
})

You can also surpress the error while the test is running using beforeEach and afterEach callbacks

beforeEach(() => {
  jest.spyOn(console, "error")
  console.error.mockImplementation(() => {})
})

afterEach(() => {
  console.error.mockRestore()
})

test('should throw', async () => {
  const app = () => throw new Error()
  expect(app).toThrow()
})
NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
1

Based on example in the Enzyme docs, it looks like you should assert that the component throws an error like so:

it("throws an error if showCancel is set to true, but no onCancel method is provided", () => {
    // Assert that an error is thrown
    const wrapper = mount(<DropTarget showCancel={ true }/>))
    const error = new Error("If `showCancel` is true, you must provide an `onCancel` method") 
    expect(wrapper).simulateError(error)
});

You may need to mount with within an <ErrorBoundary /> component (I'm not sure...) but I would try this^ and see if you have any luck.

Joe Previte
  • 114
  • 1
  • 16
  • 4
    Downvoted since `.simulateError` simulates an error within the component (useful to test if errors are being caught by `componentDidCatch` properly). The OP is asking about testing for an error that is *thrown by the component*. – Brian Adams Feb 19 '19 at 02:46