reactjstypescriptjestjsreact-testing-libraryreact-dropzone

How to test react-dropzone with Jest and react-testing-library?


I want to test onDrop method from react-dropzone library in React component. I am using Jest, React Testing Library. I'm creating mock file and I'm trying to drop this files in input, but in console.log files are still equal to an empty array. Do you have any ideas?

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);
    });
}

Solution

  • How about changing fireEvent(node, event); to fireEvent.drop(node, event);.