【问题标题】:How to properly mock `antd` Upload Dragger with jest?如何用玩笑正确模拟`antd` Upload Dragger?
【发布时间】:2021-08-25 22:14:12
【问题描述】:

我的项目中有以下反应代码

import React from 'react';
import { Upload } from 'antd';

const { Dragger } = Upload;

...

<Dragger
  accept={ACCEPTED_FORMATS}
  beforeUpload={beforeUpload}
  data-testid="upload-dragger"
  maxCount={1}
  onChange={({ file: { status } }) => {
    if (status === 'done') onUploadComplete();
  }}
  progress={progress}
  showUploadList={false}
>
{/* here i have a button, code ommited for clarity, if needed i'll post it */}
</Dragger>

我想测试一下当file.status为'done'时是否调用了回调函数onUploadComplete()

这是我现在的测试方式:

  1. 我有一个 jest.mock 来模拟一个愚蠢的请求,它总是会成功
import React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { DraggerProps } from 'antd/lib/upload';
import userEvent from '@testing-library/user-event';

import UploadCompanyLogo from '../UploadCompanyLogo'; // This is the component where the dragger is placed

jest.mock('antd', () => {
  const antd = jest.requireActual('antd');
  const { Upload } = antd;
  const { Dragger } = Upload;

  const MockedDragger = (props: DraggerProps) => {
    console.log('log test');
    return (
      <Dragger
        {...props}
        action="greetings"
        customRequest={({ onSuccess }) => {
          setTimeout(() => {
            onSuccess('ok');
          }, 0);
        }}
      />
    );
  };

  return { ...antd, Upload: { ...Upload, Dragger: MockedDragger } };
});
  1. 测试本身(与模拟文件相同的文件)在其中呈现组件(将在其中导入antd)模拟上传,然后检查是否已调用回调。
it('completes the image upload', async () => {
    const flushPromises = () => new Promise(setImmediate);

    const { getByTestId } = render(elementRenderer({ onUploadComplete }));

    const file = new File(['(⌐□_□)'], 'chucknorris.png', { type: 'image/png' });

    const uploadDragger = await waitFor(() => getByTestId('upload-dragger'));

    await act(async () => {
      userEvent.upload(uploadDragger, file);
    });

    await flushPromises();

    expect(onUploadComplete).toHaveBeenCalledTimes(1);
    expect(onUploadComplete).toHaveBeenCalledWith();
  });
  1. 元素渲染器
const elementRenderer = ({
  onUploadComplete = () => {}
}) => (
  <ApplicationProvider>
    <UploadCompanyLogo
      onUploadComplete={onUploadComplete}
    />
  </ApplicationProvider>
);
  1. 应用程序提供者
import React, { PropsWithChildren } from 'react';
import { ConfigProvider as AntdProvider } from 'antd';
import { RendererProvider as FelaProvider } from 'react-fela';
import { createRenderer } from 'fela';
import { I18nextProvider } from 'react-i18next';

import antdExternalContainer, {
  EXTERNAL_CONTAINER_ID,
} from 'src/util/antdExternalContainer';
import { antdLocale } from 'src/util/locales';
import rendererConfig from 'src/fela/felaConfig';
import i18n from 'src/i18n';

const ApplicationProvider = (props: PropsWithChildren<{}>) => {
  const { children } = props;

  return (
    <AntdProvider locale={antdLocale} getPopupContainer={antdExternalContainer}>
      <FelaProvider renderer={createRenderer(rendererConfig)}>
        <I18nextProvider i18n={i18n}>
          <div className="antd-local">
            <div id={EXTERNAL_CONTAINER_ID} />
            {children}
          </div>
        </I18nextProvider>
      </FelaProvider>
    </AntdProvider>
  );
};

export default ApplicationProvider;

这目前不起作用,但已经在@diedu 的帮助下得到了改进。

console.log() 我已放入当前未显示的 MockedDragger。如果我在组件和 mockedDragger 中都放了 console.log(),它会打印组件日志。

关于如何继续的任何提示? 我已经看到了这个issue 并没有帮助。

【问题讨论】:

  • 调用 onUploadComplete() 会发生什么?我认为这将是一个成功的信息,对吧?我建议您测试该成功消息。
  • onUploadComplete 会触发一些数据库的东西,对测试来说没有什么是非常重要的。我尝试记录一些消息,它在浏览器上运行良好(当状态为“错误”或“上传”时,因为它从未真正完成上传。我想模拟“完成”状态以确保始终调用此回调

标签: javascript reactjs jestjs antd react-testing-library


【解决方案1】:

您应该更改的第一件事是您在模拟中所做的回报。您正在返回一个名为 MockedDragger 的新组件,而不是 Dragger

  return { ...antd, Upload: { ...Upload, Dragger: MockedDragger } };

接下来是事件触发。根据this issue,您应该使用 RTL 用户事件库并将调用包装在act

import userEvent from "@testing-library/user-event";

...
  await act(async () => {
    userEvent.upload(uploadDragger, file);
  });
...

最后,由于在检查调用之前运行了一些异步代码you need to flush the pending promises

  const flushPromises = () => new Promise(setImmediate);
  ...
  await flushPromises();
  expect(onUploadComplete).toHaveBeenCalled()

这是完整版

import { render, waitFor } from "@testing-library/react";
import App from "./App";
import userEvent from "@testing-library/user-event";
import { act } from "react-dom/test-utils";
import { DraggerProps } from "antd/lib/upload";

jest.mock('antd', () => {
  const antd = jest.requireActual('antd');
  const { Upload } = antd;
  const { Dragger } = Upload;

  const MockedDragger = (props: DraggerProps) => {
    return <Dragger {...props} customRequest={({ onSuccess }) => {
      setTimeout(() => {
        onSuccess('ok');
      }, 0)
    }} />;
  };

  return { ...antd, Upload: { ...Upload, Dragger: MockedDragger } };
});

it("completes the image upload", async () => {
  const onUploadComplete = jest.fn();
  const flushPromises = () => new Promise(setImmediate);

  const { getByTestId } = render(
    <App onUploadComplete={onUploadComplete} />
  );

  const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" });

  const uploadDragger = await waitFor(() => getByTestId("upload-dragger"));
  await act(async () => {
    userEvent.upload(uploadDragger, file);
  });
  await flushPromises();
  expect(onUploadComplete).toHaveBeenCalled();
});

不幸的是,我 couldn't set up 一个代码框以显示它正在工作,但如果您遇到任何问题,请告诉我,我可以将代码推送到一个仓库。

【讨论】:

  • 非常感谢您的回答!但不幸的是仍然无法正常工作:(。我总是得到Received number of calls: 0。您需要更多信息吗?我的拖动器在一些 div 中,并且还有其他道具,例如 beforeUpload 等。
  • 另外,我不知道这有多大用处,但如果我在jest.mock 的回调中插入console.log,它永远不会记录消息。可能是因为模拟不起作用?就像,它并不是在真正地嘲笑 Dragger。只是一个假设..
  • @GabrielMichelassi 我实际上将console.log 放在了模拟中,我在运行测试时看到了它,请查看此存储库以查看与您的实际代码github.com/diedu89/antd-dragger-test 的不同之处
  • 感谢您的回购,它对我非常有用,但我仍然找不到为什么模拟对我不起作用。感谢您的努力,我会继续寻找,如果我有消息,我会在这里发布
  • @GabrielMichelassi 你能用你现在拥有的代码更新你的答案吗?我可以帮助确定可能不同的地方
猜你喜欢
  • 2021-01-06
  • 2020-02-08
  • 1970-01-01
  • 2022-10-06
  • 2021-12-30
  • 2020-12-17
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多