如何使用 Jest 和 react-testing-library 测试 react-dropzone?
Posted
技术标签:
【中文标题】如何使用 Jest 和 react-testing-library 测试 react-dropzone?【英文标题】:How to test react-dropzone with Jest and react-testing-library? 【发布时间】:2021-02-11 16:29:54 【问题描述】:我想测试 React 组件中 react-dropzone 库中的 onDrop 方法。我正在使用 Jest,React 测试库。我正在创建模拟文件,并试图将这些文件放入输入中,但在 console.log 文件中仍然等于一个空数组。你有什么想法吗?
package.json
"typescript": "^3.9.7",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.0.4",
"@types/jest": "^26.0.13",
"jest": "^26.4.2",
"ts-jest": "^26.3.0",
"react-router-dom": "^5.1.2",
"react-dropzone": "^10.1.10",
"@types/react-dropzone": "4.2.0",
ModalImportFile.tsx
import React, FC, useState from "react";
import Box, Button, Dialog, DialogContent, DialogTitle, Grid from "@material-ui/core";
import useDropzone from "react-dropzone";
import AttachFileIcon from "@material-ui/icons/AttachFile";
import DeleteIcon from "@material-ui/icons/Delete";
interface Props
isOpen: boolean;
interface Events
onClose: () => void;
const ModalImportFile: FC<Props & Events> = props =>
const isOpen = props as Props;
const onClose = props as Events;
const [files, setFiles] = useState<Array<File>>([]);
const getRootProps, getInputProps, open = useDropzone(
onDrop: (acceptedFiles: []) =>
setFiles(
acceptedFiles.map((file: File) =>
Object.assign(file,
preview: URL.createObjectURL(file),
),
),
);
,
noClick: true,
noKeyboard: true,
);
const getDragZoneContent = () =>
if (files && files.length > 0)
return (
<Box border=1 borderRadius=5 borderColor="#cecece" p=2 mb=2>
<Grid container alignItems="center" justify="space-between">
<Box color="text.primary">files[0].name</Box>
<Box ml=1 color="text.secondary">
<Button
startIcon=<DeleteIcon color="error" />
onClick=() =>
setFiles([]);
/>
</Box>
</Grid>
</Box>
);
return (
<Box border=1 borderRadius=5 borderColor="#cecece" p=2 mb=2 style= borderStyle: "dashed" >
<Grid container alignItems="center">
<Box mr=1 color="text.secondary">
<AttachFileIcon />
</Box>
<Box color="text.secondary">
<Box onClick=open component="span" marginLeft="5px">
Download
</Box>
</Box>
</Grid>
</Box>
);
;
const closeHandler = () =>
onClose();
setFiles([]);
;
return (
<Dialog open=isOpen onClose=closeHandler>
<Box width=520>
<DialogTitle>Import</DialogTitle>
<DialogContent>
<div data-testid="container" className="container">
<div data-testid="dropzone" ...getRootProps( className: "dropzone" )>
<input data-testid="drop-input" ...getInputProps() />
getDragZoneContent()
</div>
</div>
</DialogContent>
</Box>
</Dialog>
);
;
export default ModalImportFile;
ModalImportFile.test.tsx
import React from "react";
import render, screen, fireEvent from "@testing-library/react";
import ModalImportFile from "../../components/task/elements/ModalImportFile";
const props =
isOpen: true,
onClose: jest.fn(),
;
beforeEach(() => jest.clearAllMocks());
describe("<ModalImportFile/>", () =>
it("should drop", async () =>
render(<ModalImportFile ...props />);
const file = new File([JSON.stringify( ping: true )], "ping.json", type: "application/json" );
const data = mockData([file]);
function dispatchEvt(node: any, type: any, data: any)
const event = new Event(type, bubbles: true );
Object.assign(event, data);
fireEvent(node, event);
function mockData(files: Array<File>)
return
dataTransfer:
files,
items: files.map(file => (
kind: "file",
type: file.type,
getAsFile: () => file,
)),
types: ["Files"],
,
;
const inputEl = screen.getByTestId("drop-input");
dispatchEvt(inputEl, "dragenter", data);
);
【问题讨论】:
似乎 dropzone 方面提供的官方测试示例是如此糟糕和混乱,并且某些部分无法正常工作。您是否找到任何方法来测试包含此组件和 drop 事件的组件? @PouyaJabbarisani 我重写了测试组件,请看我的回答 【参考方案1】:将fireEvent(node, event);
更改为fireEvent.drop(node, event);
怎么样。
【讨论】:
欢迎来到 Stack Overflow。虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。 How to Answer 这对我没有帮助。文件仍然等于一个空数组 我将fireEvent(node, event);
更改为fireEvent.drop(node, event);
,并在最后一行添加了await waitFor(() => expect(screen.getByText("ping.json")).toBeInTheDocument());
,测试通过了。【参考方案2】:
根据 rokki 的回答 (https://***.com/a/64643985/9405587),我重写了测试组件以便于理解。
ModalImportFile.test.tsx
import React from "react";
import render, screen, fireEvent from "@testing-library/react";
import ModalImportFile from "../../components/task/elements/ModalImportFile";
const props =
isOpen: true,
onClose: jest.fn(),
;
beforeEach(() => jest.clearAllMocks());
describe("<ModalImportFile/>", () =>
it("should drop", async () =>
render(<ModalImportFile ...props />);
window.URL.createObjectURL = jest.fn().mockImplementation(() => "url");
const inputEl = screen.getByTestId("drop-input");
const file = new File(["file"], "ping.json",
type: "application/json",
);
Object.defineProperty(inputEl, "files",
value: [file],
);
fireEvent.drop(inputEl);
expect(await screen.findByText("ping.json")).toBeInTheDocument();
【讨论】:
以上是关于如何使用 Jest 和 react-testing-library 测试 react-dropzone?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 jest.mock 模拟 useRef 和反应测试库
如何在 TypeScript 中使用 Jest 和 Knex 进行测试?