Sinon 假计时器在测试中多次调用仅触发一次

Sinon Fake Timer Call multiple Times In Test Only Firing Once

我有一个递归调用自身的函数,直到它调用的函数完成。 这是正在测试的函数(我已经修改它以便在 Whosebug 上 post 因为它是专有的。):

private async awaitQueryCompletion(queryId: string): Promise<void> {
    setTimeout(async () => {
      const output: ExecutionOutput =
        await this.getQueryExecution({ QueryExecutionId: queryId }).promise();

      let state: string | undefined;
      if (ExecutionOutput.QueryExecution !== undefined && ExecutionOutput.QueryExecution.Status) {
        state = ExecutionOutput.QueryExecution.Status.State;
      }

      if (state !== undefined && state === "RUNNING") {
        await this.awaitQueryCompletion(queryId);
      }
    }, this.RETRY_INTERVAL);
  }

这是我的测试: 设置:

beforeEach(() => {
    sandbox = createSandbox();
    getQueryExecutionStub = sandbox.stub(QueryClass, "getQueryExecution")
    timer = sandbox.useFakeTimers({ shouldAdvanceTime: true});
});
 it.only("Should call getQueryExecution twice with correct params", async () => {
      const INTERVAL: number = 5010;
      getQueryExecutionStub.onFirstCall()  
        .returns({
          promise: async (): Promise<ExecutionOutput> => {
            return Promise.resolve({
              QueryExecution: {
                Status: {
                  State: "RUNNING"
                }
              }
            });
          }
        });

      getQueryExecutionStub.onSecondCall()
        .returns({promise: async (): Promise<ExecutionOutput> => {
            return Promise.resolve({
              QueryExecution: {
                Status: {
                  State: "SUCCEEDED"
                }
              }
            });
          }
        });

      await selector.query(testInput);
      timer.tick(INTERVAL);
      timer.tick(INTERVAL);

      expect(getQueryExecutionStub.calledTwice).to.equal(true);
    });
  });

我想要的是 getQueryExecutionStub 被调用两次,所以我正在模拟 setTimeout 函数并尝试按想法行事发生了两个超时周期。我有一次达到 运行 超时,但我不知道如何再次达到 运行。任何和所有帮助将不胜感激!我查看了两个 lolex 文档:(https://github.com/sinonjs/lolex) and sinon fake timers docs (https://sinonjs.org/releases/v8.0.4/fake-timers/).

所以我在稍微挖掘之后就能弄明白这一点。

private async awaitQueryCompletion(queryId: string, context: Context): Promise<void> {

    return new Promise(async (resolve: Function, reject: Function): Promise<void> => {
      // tslint:disable-next-line: no-inferred-empty-object-type
      this.timeout(async () => {
        try {
          log.debug("Checking query completion");
          const queryExecutionOutput: Athena.GetQueryExecutionOutput =
            await this.athenaClient.getQueryExecution({ QueryExecutionId: queryId }).promise();

          let state: string | undefined;
          if (queryExecutionOutput.QueryExecution !== undefined
            && queryExecutionOutput.QueryExecution.Status !== undefined) {
            state = queryExecutionOutput.QueryExecution.Status.State;
          }

          if (state !== undefined && state === "RUNNING") {
            if (context.getRemainingTimeInMillis() > this.TIMEOUT_PADDING_MS) {
              await this.awaitQueryCompletion(queryId, context);
              resolve();
            } else {
              log.error(`Failure: Unable to complete query before lambda shut down...`);
              reject();
            }

          } else if (state === "SUCCEEDED") {
            resolve();
          } else if (state === "FAILED") {
            throw new Error(state);
          } else {
            log.error("Unable to determine the state of the query...");
            reject();
          }


        } catch (e) {
          log.error(`${JSON.stringify(e)}`);
          return reject(e);
        }
      }, this.RETRY_INTERVAL_MS);
    });
  }

我需要的是将我的函数包装在一个承诺中,并且在每个 tick 解决之后,下一个 tick 的承诺可以触发。