【问题标题】:Mock axios create in test file. React, typescript模拟 axios 在测试文件中创建。反应,打字稿
【发布时间】:2021-06-01 09:53:38
【问题描述】:

我看过一些关于模拟 axios 的类似帖子,但我花了几个小时,但我没有设法解决我的问题并让我的测试工作。我尝试了我找到的解决方案,但没有奏效。

我正在使用 React、Typescript、react-query、axios 编写小应用程序。我使用 React 测试库、Jest、Mock Service Worker 编写测试。 为了测试删除元素功能,我只想模拟 axios 删除功能并检查它是否使用正确的参数调用。 这是问题: 我正在使用 axios 实例:

//api.ts
const axiosInstance = axios.create({
  baseURL: url,
  timeout: 1000,
  headers: {
    Authorization: `Bearer ${process.env.REACT_APP_AIRTABLE_API_KEY}`,
  },
//api.ts
export const deleteRecipe = async (
  recipeId: string
): Promise<ApiDeleteRecipeReturnValue> => {
  try {
    const res = await axiosInstance.delete(`/recipes/${recipeId}`);
    return res.data;
  } catch (err) {
    throw new Error(err.message);
  }
};
});
//RecipeItem.test.tsx 
import axios, { AxiosInstance } from 'axios';

jest.mock('axios', () => {
  const mockAxios = jest.createMockFromModule<AxiosInstance>('axios');
  return {
    ...jest.requireActual('axios'),
    create: jest.fn(() => mockAxios),
    delete: jest.fn(),
  };
});

test('delete card after clicking delete button ', async () => {
  jest
    .spyOn(axios, 'delete')
    .mockImplementation(
      jest.fn(() =>
        Promise.resolve({ data: { deleted: 'true', id: `${recipeData.id}` } })
      )
    );

  render(
    <WrappedRecipeItem recipe={recipeData.fields} recipeId={recipeData.id} />
  );
  const deleteBtn = screen.getByRole('button', { name: /delete/i });
  user.click(deleteBtn);

  await waitFor(() => {
    expect(axios.delete).toBeCalledWith(getUrl(`/recipes/${recipeData.id}`));
  });
});

在测试中出现错误“错误:无法读取未定义的属性‘数据’”

但是,如果我不使用 axios 实例并使用如下代码,则测试将起作用。

//api.ts
const res = await axios.delete(`/recipes/${recipeId}`);

我迷路了,卡住了。对于我在stackoverflow上发现的类似问题,我已经尝试了很多事情和一些答案,但它们对我不起作用。有人可以帮忙吗? 我不想在 mocks 中模拟 axios 模块,只在特定的测试文件中。 我也没有打字稿和测试方面的经验。我写的这个项目是为了学习。

【问题讨论】:

    标签: reactjs testing axios jestjs mocking


    【解决方案1】:

    我找到了一些解决方法,至少它有效。我将 axiosInstance 声明移到了一个单独的模块中,然后我模拟了这个模块并删除了函数。

    //RecipeItem.test.tsx
    jest.mock('axiosInstance', () => ({
      delete: jest.fn(),
    }));
    
    test('delete card after clicking delete button and user confirmation', async () => {
      jest
        .spyOn(axiosInstance, 'delete')
        .mockImplementation(
          jest.fn(() =>
            Promise.resolve({ data: { deleted: 'true', id: `${recipeData.id}` } })
          )
        );
      render(
        <WrappedRecipeItem recipe={recipeData.fields} recipeId={recipeData.id} />
      );
      const deleteBtn = screen.getByRole('button', { name: /delete/i });
      user.click(deleteBtn);
    
      await waitFor(() => {
        expect(axiosInstance.delete).toBeCalledWith(`/recipes/${recipeData.id}`);
      });
    });
    

    如果你有更好的解决方案,我想看看。

    【讨论】:

    • 一个小观察:如果您要做的只是 expect(axiosInstance.delete).toBeCalledWith(...),则不需要为 axiosInstance.delete 提供 mockImplementation
    猜你喜欢
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    • 2022-01-06
    • 2017-07-07
    相关资源
    最近更新 更多