Why Jest's toThrow won't work when create

2020-07-05 06:28发布

问题:

class TestObject {
  constructor(value) {
    if (value === null || value === undefined) {
      throw new Error('Expect a value!');
    }
  }
}

describe('test the constructor', () => {
  test('it works', () => {
    expect(() => {
      new TestObject();
    }).toThrow();
  });

  test('not work', () => {
    expect(new TestObject()).toThrow();
  });
});

2 Test cases here, one works and the other not.

The failing message for the not work one is as the following:

● test the constructor › not work

Expect a value!

 at new TestObject (tests/client/utils/aaa.test.js:4:11)
 at Object.<anonymous> (tests/client/utils/aaa.test.js:17:12)
     at Promise (<anonymous>)
     at <anonymous>
 at process._tickCallback (internal/process/next_tick.js:188:7)

Why do I need to wrap that call in a function call, we don't need to wrap when the function just return a plain value, or even a promise, we can use async/await to check that in expect() rather than create a function inside expect().

What happened here?

回答1:

Here

expect(new TestObject()).toThrow();

new TestObject() is evaluated first, then expect(...), then ...toThrow(), in accordance with operator precedence. When new TestObject() throws, anything else doesn't matter.

This is why toThrow expects a function that is supposed to throw:

expect(() => {
  new TestObject();
}).toThrow();

This way it can be wrapped with try..catch internally when being called.

It works similarly in Jasmine toThrow and Chai to.throw assertions as well.