Jest API与done()类似,但在异步测试中使用多个回调

6za6bjd0  于 2022-12-08  发布在  Jest
关注(0)|答案(1)|浏览(171)

我在jest中有一些测试用例,它们依赖于Assert在setTimeout之后调用一个或多个回调来测试异步特性。示例

function publish(eventName, args) {
  const callbacks = getAllCallbacks(eventName);
  // Subscriptions being called asynchronously
  setTimeout(() => {
    callbacks.forEach(cb => {
      callback(...args);
    });
  }, 1000);
}

// Example 1
it('test 1 callback after executed twice', (done) => {
  const callback = jest.fn((arg) => {
    expect(arg).toBe('some value');
    done() // but done should be called after being called the second time
  })
  subscribe('eventName', callback);
  publish('eventName', args); // first publish
  publish('eventName', args); // second publish
  expect(callback).toHaveBeenCalledTimes(2); // but callback will be called after 5 seconds
});

// Example 2
it('test 1 callback after executed twice', (done) => {
  const callback1 = jest.fn((arg) => {
    expect(arg).toBe('some value');
    done() // but done should be called after all callbacks were executed
  })
  const callback2 = jest.fn((arg) => {
    expect(arg).toBe('some value');
    done() // but done should be called after all callbacks were executed
  })
  subscribe('eventName', callback);
  subscribe('eventName', callback2);
  publish('eventName', args);

  expect(callback1).toHaveBeenCalledTimes(1); // but callback will be called after 5 seconds
  expect(callback2).toHaveBeenCalledTimes(1); // but callback will be called after ~1 second
});

上述测试用例是不正确的,因为在执行“ALL”回调后未调用done,并且expect().toHaveBeenCalledTimes()也不会异步执行。

fnvucqvd

fnvucqvd1#

我可以使用的方法之一是创建HOC。

// Helper
function mockCallbacks(_done: any) {
  let count = 0;
  return (callback: any, callCounts = 0) => {
    count = callCounts || count + 1;
    return jest.fn((...args) => {
      callback(...args);
      // eslint-disable-next-line no-plusplus
      if (--count === 0) {
        _done();
      }
    });
  };
}

// Usage
it('test same callback multiple times', done => {
  const mocker = mockCallbacks(done);

  const callback = mocker((data: any) => {
    expect(data).toBe('something');
  }, 2);
  subscribe('eventName', callback);
  publish('eventName');
  publish('eventName');
});

// OR 
it('test multiple callbacks', done => {
  const mocker = mockCallbacks(done);

  const callback1 = mocker((data: any) => {
    expect(data).toBe('something');
  });
  const callback2 = mocker((data: any) => {
    expect(data).toBe('something');
  });
  
  subscribe('eventName', callback1);
  subscribe('eventName', callback2);
  publish('eventName');
});

虽然它帮助解决了大多数用例,但在执行所有回调之后等待回调执行Assert的挑战仍然存在。即,测试callback.toHaveBeenCalled()仍然很困难,因为它在setTimeout回调之前执行。

相关问题