如何使用Jest和react-testing-library测试react-dropzone?

问题描述

我想从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();
}