-1

I have a simple function as below

function foo({ platform }) {
  if (platform === 'all') {
    throw new Error('Platform value can only be android or ios');
  }
  
  return `${platform}`;
}

Then I wrote unit testing as below

it('should return correct result with platform', () => {
    expect(foo({ platform: 'ios' })).toBe('ios');
    expect(foo({ platform: 'android' })).toBe('android');
    expect(foo({platform: 'all'})).toThrow(new Error('Platform value can only be android or ios'));
  });

The test actually failed due to last test case without any useful information

 FAIL  src/utils/__test__/foo.test.ts
  ● foo() › should return correct result with platform

    Platform value can only be android or ios

      16 | }) {
      17 |   if (platform === 'all') {
    > 18 |     throw new Error('Platform value can only be android or ios');
         |           ^
      19 |   }
      20 |   
      21 |   return `${platform}`;

      at xx (src/utils/foo.ts:18:11)

I've also tried to wrapped the entire expect with try catch block but the test is not passing either

Isaac
  • 12,042
  • 16
  • 52
  • 116

1 Answers1

4

toThrow only works when expect is passed a no-arg function that can be called to cause the exception.

/* this is the only test that needs this */
expect(() => foo({platform: 'all'})).toThrow();

This is because JavaScript does not support auto-deferring function arguments so there's no way for expect to "pause" the evaluation of its arguments. So the API has to be "give me (Jest) a function to call and I'll call it when I'm ready to handle what that function might do".

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • 5
    For future users who had the same problem as me and stumble on this answer in there search: If the function in the expect is async, then use `rejects` for your test: `expect(async function).rejects.toThrow()` – bas Oct 03 '22 at 08:37