Sinon Поддельный таймер звонит несколько раз в тесте только один раз - PullRequest
0 голосов
/ 09 января 2020

У меня есть функция, которая вызывает себя рекурсивно, пока не вызовет функцию, которую она вызывает. Вот тестируемая функция (я изменил ее, чтобы опубликовать в Stackoverflow, поскольку она проприетарна.):

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), так и документы поддельных таймеров sinon (https://sinonjs.org/releases/v8.0.4/fake-timers/).

1 Ответ

0 голосов
/ 22 января 2020

Так что я смог понять это после небольшого копания.

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.

...