【问题标题】:How to properly have jest axios mock wait before resolving promise如何在解决承诺之前正确地让 jest axios 模拟等待
【发布时间】:2021-02-17 06:23:41
【问题描述】:

我有这样的功能:

join(): void {
    this.working.value = true;
    if (this.info.value) {
      axios.get('/url')
        .then((result: ResultStatus) => {
          this.result = result;
        })
        .catch((reason: AxiosError) => {
          this.showError(AjaxParseError(reason));
        })
        .finally(() => {
          this.working.value = false;
        });
    }
  }

我想为此编写一些单元测试。我要编写的第一个单元测试是测试 'this.saving' 是否设置为 true,以确保我的 UI 具有可用于显示加载指示器的值。

但是,当我使用 jest 模拟 axios 时,jest 会立即解决 axios 承诺,并且我没有机会测试在调用 then/finally 块之前会发生什么。这是我的单元测试代码的样子:

import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

import successResponse from './__json__/LeagueJoinInfoSuccess.json';

describe('constructor:', () => {
    let vm: classUnderTest;
    beforeEach(() => {
      vm = new classUnderTest();
      mockedAxios.get.mockResolvedValue({ data: successResponse }); // set up the response
      vm.join(); // the function under test
    });
    it('should set working true before calling the server to join', () => {
      expect(vm.working.value).toBeTruthy();
    });
    it('should set working false after calling the server responds', async () => {
      await flushPromises();
      expect(vm.working.value).toBeFalsy();
    });
});

第一个期望语句总是错误的,因为 finally 块在我有机会执行 await flushPromises(); 之前运行。所以工作值总是假的。

有没有一种方便的方法可以让 jest 的 axios 模拟在解决其承诺之前等待?

更新:现在有一件非常奇怪的事情:如果我将 BeforeEach 的内容移动到每个测试中,那么它的行为方式就像我希望的那样。我想我会开玩笑地打开一个问题并问他们发生了什么事。

【问题讨论】:

  • 该行为在文档中的Setup and Teardown 文章中进行了解释
  • @Teneff 我刚刚阅读了您引用的文档,它根本没有解释发生了什么。里面没有关于如何处理模拟 axios 承诺的内容。我所看到的是,在 before* 函数中调用 axios 调用会自动立即解决 promise,但在测试中调用相同的 axios 调用并不会立即解决 promise,您必须在测试中 flushPromises()。跨度>

标签: javascript unit-testing axios jestjs


【解决方案1】:

我有一个解决方案让您创建一个承诺作为响应,但是,我们不会在第一个测试用例中解决它以保持您测试加载状态,然后在第二个测试中解决它,如下所示:

describe('constructor:', () => {

  let vm: classUnderTest;

  // Resolve function
  let resolveFn: (value?: unknown) => void

  beforeEach(() => {
    vm = new classUnderTest();

    const promise = new Promise(resolve => {
      // hold the resolve function to call in 2nd test
      resolveFn = resolve;
    });
    mockedAxios.get.mockImplementation(() => promise);

    vm.join(); // the function under test
  });

  it('should set working true before calling the server to join', () => {
    expect(vm.working.value).toBeTruthy();
  });

  it('should set working false after calling the server responds', async () => {
    // resolve the pending promise
    resolve({
      data: successResponse,
    });

    // I think you would wait the promise resolved
    await new Promise(resolve => setTimeout(resolve));

    expect(vm.working.value).toBeFalsy();
  });
});

【讨论】:

  • 是的,我知道这一点,但是当和样板时非常麻烦。我希望这不是唯一的解决方案。但我同意这绝对是一个解决方案。您需要做的就是在您等待新的 Promise() 的地方等待 flushPromises()。感谢您的回答。
猜你喜欢
  • 2018-12-14
  • 2022-01-22
  • 2022-11-21
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
相关资源
最近更新 更多