如何使用 Jest 和 react-testing-library 测试 react-dropzone?
How to test react-dropzone with Jest and react-testing-library?
我想在 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);
});
}
如何将 fireEvent(node, event);
更改为 fireEvent.drop(node, event);
。
根据 rokki 的回答 (),我重写了测试组件以便于理解。
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();
}
我想在 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);
});
}
如何将 fireEvent(node, event);
更改为 fireEvent.drop(node, event);
。
根据 rokki 的回答 (
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();
}