在 Jest 中测试异步代码:done() 未按预期调用

abr*_*raj 6 javascript unit-testing jestjs

这是用 Jest (v20.0.4) 编写的测试套件。

前 3 个测试是预期行为,我的问题与 Test4 相关。

test('Test1: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(7);
});
// > Passes as expected
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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"
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

在 Test4 中,在语句done()之后立即调用expect
因此,即使期望语句没有通过,我猜它应该会失败,并出现类似于 Test2 的错误:(Expected array: [1, 2, 7, 9] To contain value: 8)

然而,它失败并出现超时错误,如上所示,这表明它done()从未被调用。

为什么?我不明白!

有人可以指导我完成这种行为吗?

我浏览了文档但找不到与此相关的任何内容。

ggo*_*len 6

在您的代码中,expect调用会抛出并且done永远不会到达。因此,Jest 会一直等到超时并发出您注意到的令人讨厌的、不清楚的错误。

解决方案是捕获抛出并调用done(error)以向 Jest 运行程序指示测试失败。

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);
});
Run Code Online (Sandbox Code Playgroud)

运行此命令可以得到所需的结果:

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

Expected value: 8
Received array: [1, 2, 7, 9]
Run Code Online (Sandbox Code Playgroud)

来自文档

如果该expect语句失败,则会抛出错误并且done()不会被调用。如果我们想在测试日志中查看失败的原因,我们必须包装expect在一个块中并将块try中的错误传递给. 否则,我们最终会遇到不透明的超时错误,该错误不会显示 接收到的值。catchdoneexpect(data)


Rey*_*cke 0

我发现setTimeoutJest 并不像人们想象的那样有效。但有一个很好的方法来处理它:

  • 在测试开始时,您可以告诉 Jest 使用 fakeTimers: jest.useFakeTimers();

  • 当您需要执行回调时,可以使用以下命令触发它jest.runAllTimers();

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