最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Testing asynchronous code in Jest: done() not being called as expected - Stack Overflow

programmeradmin0浏览0评论

Here is a test suite written in Jest (v20.0.4).

The first 3 tests are expected behaviour, my question lies related to Test4.

test('Test1: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(7);
});
// > Passes as expected
test('Test2: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(8);
});
// > Fails as expected; Expected array: [1, 2, 7, 9] To contain value: 8
test('Test3: the list should contain 7', (done) => {
  function callback(data) {
    expect(data).toContain(7);
    done();
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});
// > Passes as expected
test('Test4: the list should contain 7', (done) => {
  function callback(data) {
    expect(data).toContain(8);
    done();
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});
// > Fails with Error "Timeout - Async callback was not invoked within timeout specified"

Here is my question:

In Test4, done() is called immediately after the expect statement.
So, even if the expect statement does not pass, I guessed it should fail with error similar to Test2: (Expected array: [1, 2, 7, 9] To contain value: 8)

However, it fails with a timeout error as shown above which suggests that done() is never called.

Why? I don't get it!

Can someone please guide me through this behaviour?

I scanned through the docs but could not find anything related to this.

Here is a test suite written in Jest (v20.0.4).

The first 3 tests are expected behaviour, my question lies related to Test4.

test('Test1: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(7);
});
// > Passes as expected
test('Test2: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(8);
});
// > Fails as expected; Expected array: [1, 2, 7, 9] To contain value: 8
test('Test3: the list should contain 7', (done) => {
  function callback(data) {
    expect(data).toContain(7);
    done();
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});
// > Passes as expected
test('Test4: the list should contain 7', (done) => {
  function callback(data) {
    expect(data).toContain(8);
    done();
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});
// > Fails with Error "Timeout - Async callback was not invoked within timeout specified"

Here is my question:

In Test4, done() is called immediately after the expect statement.
So, even if the expect statement does not pass, I guessed it should fail with error similar to Test2: (Expected array: [1, 2, 7, 9] To contain value: 8)

However, it fails with a timeout error as shown above which suggests that done() is never called.

Why? I don't get it!

Can someone please guide me through this behaviour?

I scanned through the docs but could not find anything related to this.

Share Improve this question edited Feb 15, 2021 at 19:05 ggorlen 57.9k8 gold badges114 silver badges157 bronze badges asked Oct 2, 2018 at 7:42 abrajabraj 3493 silver badges15 bronze badges 1
  • I believe Jest returns as soon as it sees a failing expect statement. But any ideas regarding how to call done() immediately after failing expect, rather than waiting for Timeout to happen. – abraj Commented Oct 2, 2018 at 7:49
Add a ment  | 

2 Answers 2

Reset to default 7

In your code, the expect call throws and done is never reached. As such, Jest waits until it times out and emits the nasty, unclear error you noticed.

The solution is to catch the throw and call done(error) to indicate to the Jest runner that the test failed.

test('Test4: the list should contain 7', done => {
  function callback(data) {
    try {
      expect(data).toContain(8);
      done();
    }
    catch (err) {
      done(err);
    }
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});

A run of this gives the desired result:

Error: expect(received).toContain(expected) // indexOf

Expected value: 8
Received array: [1, 2, 7, 9]

From the docs:

If the expect statement fails, it throws an error and done() is not called. If we want to see in the test log why it failed, we have to wrap expect in a try block and pass the error in the catch block to done. Otherwise, we end up with an opaque timeout error that doesn't show what value was received by expect(data).

I found that setTimeout and Jest don't work as one might think. But there is a good way to deal with it:

  • At the start of your test you can tell Jest to use fakeTimers: jest.useFakeTimers();

  • When you need the callback to be executed you can trigger it with jest.runAllTimers();

https://jestjs.io/docs/en/timer-mocks.html

发布评论

评论列表(0)

  1. 暂无评论