如何确保在 axios 调用中 onUploadProgress 回调已被覆盖在单元测试中

3
我在ReactJS中使用axios调用API上传文件到服务器。 我使用axios中的onUploadProgress回调来跟踪和显示上传进度条。
但是,我很难在我的Jest单元测试用例中覆盖onUploadProgress回调。 虽然我能够模拟axios调用并返回解决Promise与mock响应,但在我的测试覆盖率中,它显示在onUploadProgress回调内编写的所有行都未被覆盖。
我需要确保测试用例中覆盖onUploadProgress回调内的所有内容。 这可以通过更改axios的模拟实现或模拟作为输入传递给axios的参数/配置来完成,但我无法找出如何实现。
以下是我的实际API逻辑:
export async function uploadAttachmentsApi(files: any[], progress: number[], setProgress: Function): Promise<string[]> {
  const apiUrl = 'some api url';
  const promises: any = [];
  const uploadProgress: number[] = [];

  for (let x = 0; x < files.length; x += 1) {
    const data = new FormData();
    data.append('file', files[x]);

    const promise = axiosApi(apiUrl, {
      method: 'post',
      data,
      onUploadProgress: (progressEvent) => {
        uploadProgress[x] = Math.round((100 * progressEvent.loaded) / progressEvent.total);
        setProgress([...uploadProgress, ...progress]);
      },
    });

    promises.push(promise);
  }

  return Promise.all(promises);
}

以下是我对上述代码的单元测试用例。
describe('upload-attachment-api', () => {
  it('uploadAttachments should make post call', async () => {
    const files: any[] = [
      {
        name: 'file1.doc',
        size: '1024',
        type: 'txt/plain',
        lastModifiedOn: new Date('2021-05-03'),
      },
    ];
    const urls = ['C:\\EmailAttachments\\154\\file1.doc', 'C:\\EmailAttachments\\154\\file2.pdf'];
    const progress = [100];
    const setProgress = jest
      .fn()
      .mockImplementationOnce((uploadProgress: number[]) => [...uploadProgress, ...progress]);
    const axiosCall = jest.spyOn(common, 'axiosApi').mockImplementationOnce(() => Promise.resolve(urls));

    const result = await uploadAttachmentsApi(files, progress, setProgress);

    expect(axiosCall).toBeCalled();
    expect(result[0]).toEqual(urls);
  });
});

注意:我在上面使用的axiosApi是我们组织创建的实际axios包的封装器。因此,我不能直接模拟axios包或使用AxiosMockAdapter。
以下是axiosApi封装器的简要介绍。
function axiosApi(url, options) {
  var modifiedOptions = options || {};
  modifiedOptions.url = url;
  modifiedOptions.headers.Authorization = //Bearer token from common redux store received from company's SSO
  return axios.request(modifiedOptions).then(function (response) {
    return response.data;
  });
}

感谢任何帮助


我有同样的问题,希望有人能尽快回答。 与此同时,你尝试过这个gist吗? - p6l-richard
1个回答

0

我刚刚遇到了同样的问题,设置类似。也许对于OP来说已经不相关了,但以防万一有人需要,这是我如何为我的onUploadProgress函数获得100%的行覆盖率:

在测试文件中,模拟API包装文件:

jest.mock("util/apiWrapper", () => ({
  axiosApi: ("<URL>", {onUploadProgress}) => 
    onUploadProgress({loaded: 20, total: 1024})
}))

现在当你运行测试时,它将调用axiosApi的模拟实现,但会在运行时将onUploadProgress的实际实现作为参数传递。然后作为返回值,你调用实际函数onUploadProgress并传入模拟值。由于你调用了实际函数,执行将进入你的代码,从而获得所需的覆盖率。
对于这个测试用例来说,URL参数是无关紧要的,你可以传入任何字符串。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接