问题描述
我想从React组件中的react-dropzone库测试onDrop方法。我正在使用React测试库Jest。我正在创建模拟文件,并试图在输入中删除此文件,但在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);
});
}
解决方法
如何将fireEvent(node,event);
更改为fireEvent.drop(node,event);
。
使用rokki的答案(https://stackoverflow.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();
}