等待火灾回调并开玩笑地忘记事件

Wait for callback from a fire and forget event in jest

我在开玩笑地构建集成测试时遇到一种情况,我的被测产品将“在某个时候”调用回调。被测代码是通过 rpc“连接”(模拟为内存消息)调用事件触发的,但是连接通知 API returns 立即,而不是等待所有异步进程停止。

所以我们有这样的设置:

test.tsx
//...preamble...
it('fire and forget with callback', async () => {
  const receivedRequests = [];
  clientConnection.onRequest(requestData => {
    receivedRequests.push(requestData);
    if (receivedRequests.length == 5) {
      signal.release();
    }
  });

  clientConnection.sendNotification(usefulTestData);
  // wait for a signal on 
  await signal.waitAsync();
  expect(receivedRequests).toEqual(expectedTestDataArrFromFile);
});

server.tsx
// ...preamble...

Server() {
// ...
    //onNotification handler callback's return type is void, not Promise
    this.connection.onNotification((notificationData) => this.handleNotification(notificationData));

    private async function handleNotification(data) {
      // do something interesting
      await this.connection.sendRequest(requestData);
      // do more...
    }

这里的 connection 对象是通过模拟 RPC 进行通信的不同对象。客户端连接上的 sendNotification 最终调用服务器的 onNotification,反之亦然。

在不更改合约的情况下,如何在回调中创建信号以仅有条件地允许测试继续执行?

灵感来自 https://github.com/microsoft/vscode-languageserver-node/issues/747

以下代码能够异步等待事件:

      const emitter = new events.EventEmitter();

      client.onNotification("textDocument/didOpen/processed", () =>
      {
        emitter.emit("notificationProcessed");
      });

      client.sendNotification(
        "textDocument/didOpen",
        openParams,
      );

      await new Promise((resolve) => {
        emitter.on("notificationProcessed", (_args) => {
          resolve();
        })
      });

这里我们有一个事件发射器,一旦发射后忘记事件完成,它就会被发射。

测试上下文创建一个新的 Promise,它只会在事件触发后解析(并因此允许测试上下文继续执行)。