admin 管理员组

文章数量: 1086019

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

本文标签: javascriptTesting asynchronous code in Jest done() not being called as expectedStack Overflow