javascript - 如何正确地 mock `antd` Upload Dragger?

标签 javascript reactjs jestjs antd react-testing-library

我的项目中有以下 react 代码

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>
我想测试一下回调函数 onUploadComplete()当 file.status 为 'done' 时调用.
这是我现在进行测试的方式:
  • 我有一个 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 } };
    });
    
  • 测试本身(与模拟相同的文件),它在其中呈现组件(将导入 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();
      });
    
  • 元素渲染器
  • const elementRenderer = ({
      onUploadComplete = () => {}
    }) => (
      <ApplicationProvider>
        <UploadCompanyLogo
          onUploadComplete={onUploadComplete}
        />
      </ApplicationProvider>
    );
    
  • 应用程序提供商
  • 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。如果我放一个 console.log()在组件和 mockedDragger 中,它都会打印组件日志。
    关于如何进行的任何提示?
    我已经看到了 issue并没有帮助。

    最佳答案

    您应该更改的第一件事是您在模拟中所做的返回。您正在返回一个名为 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一个代码框来显示它正在工作,但是如果您遇到任何问题,请告诉我,我可以将代码推送到存储库。

    关于javascript - 如何正确地 mock `antd` Upload Dragger?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67895146/

    相关文章:

    javascript - 变量 getElementbyId 内部函数

    javascript - DYGraphs:使用一个 RangeSelector 控制多个图形

    Javascript |用于替换当前窗口位置的链接/书签

    javascript - 如何在本地主机上执行React D3组件

    javascript - document.getElementById().innerHTML 未在 ReactJS 中获取文本

    javascript - Karma 单元测试 : Module name "react" has not been loaded yet for context: _. 使用 require([])

    javascript - 使用 React Hooks 将延迟添加到 map 中

    javascript - 使用 async/await 时 try/catch 中的范围问题

    javascript - Jest |模拟 JavaScript 创建并注入(inject)的样式表

    reactjs - enzyme shallowWrapper.setState 不适用于redux 连接组件