/* eslint react/prop-types: 0, jsx-a11y/label-has-for: 0 */ import React, { createRef } from "react"; import { act, cleanup, fireEvent, render } from "@testing-library/react"; import { renderHook } from "@testing-library/react-hooks"; import { fromEvent } from "file-selector"; import * as utils from "./utils"; import Dropzone, { useDropzone } from "./index"; describe("useDropzone() hook", () => { let files; let images; beforeEach(() => { files = [createFile("file1.pdf", 1111, "application/pdf")]; images = [ createFile("cats.gif", 1234, "image/gif"), createFile("dogs.gif", 2345, "image/jpeg"), ]; }); afterEach(cleanup); describe("behavior", () => { it("renders the root and input nodes with the necessary props", () => { const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.innerHTML).toMatchSnapshot(); }); it("sets {accept} prop on the ", () => { const accept = { "image/jpeg": [], }; const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).toHaveAttribute( "accept", "image/jpeg" ); }); it("updates {multiple} prop on the when it changes", () => { const { container, rerender } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).toHaveAttribute( "accept", "image/jpeg" ); rerender( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).toHaveAttribute( "accept", "image/png" ); }); it("sets {multiple} prop on the ", () => { const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).toHaveAttribute("multiple"); }); it("updates {multiple} prop on the when it changes", () => { const { container, rerender } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).not.toHaveAttribute("multiple"); rerender( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).toHaveAttribute("multiple"); }); it("sets any props passed to the input props getter on the ", () => { const name = "dropzone-input"; const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("input")).toHaveAttribute("name", name); }); it("sets any props passed to the root props getter on the root node", () => { const ariaLabel = "Dropzone area"; const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("div")).toHaveAttribute( "aria-label", ariaLabel ); }); it("runs the custom callback handlers provided to the root props getter", async () => { const event = createDtWithFiles(files); const rootProps = { onClick: jest.fn(), onKeyDown: jest.fn(), onFocus: jest.fn(), onBlur: jest.fn(), onDragEnter: jest.fn(), onDragOver: jest.fn(), onDragLeave: jest.fn(), onDrop: jest.fn(), }; const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); const dropzone = container.querySelector("div"); fireEvent.click(dropzone); expect(rootProps.onClick).toHaveBeenCalled(); fireEvent.focus(dropzone); fireEvent.keyDown(dropzone); expect(rootProps.onFocus).toHaveBeenCalled(); expect(rootProps.onKeyDown).toHaveBeenCalled(); fireEvent.blur(dropzone); expect(rootProps.onBlur).toHaveBeenCalled(); await act(() => fireEvent.dragEnter(dropzone, event)); expect(rootProps.onDragEnter).toHaveBeenCalled(); fireEvent.dragOver(dropzone, event); expect(rootProps.onDragOver).toHaveBeenCalled(); fireEvent.dragLeave(dropzone, event); expect(rootProps.onDragLeave).toHaveBeenCalled(); await act(() => fireEvent.drop(dropzone, event)); expect(rootProps.onDrop).toHaveBeenCalled(); }); it("runs the custom callback handlers provided to the input props getter", async () => { const inputProps = { onClick: jest.fn(), onChange: jest.fn(), }; const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); const input = container.querySelector("input"); fireEvent.click(input); expect(inputProps.onClick).toHaveBeenCalled(); await act(async () => fireEvent.change(input, { target: { files: [] } })); expect(inputProps.onChange).toHaveBeenCalled(); }); it("runs no callback handlers if {disabled} is true", async () => { const event = createDtWithFiles(files); const rootProps = { onClick: jest.fn(), onKeyDown: jest.fn(), onFocus: jest.fn(), onBlur: jest.fn(), onDragEnter: jest.fn(), onDragOver: jest.fn(), onDragLeave: jest.fn(), onDrop: jest.fn(), }; const inputProps = { onClick: jest.fn(), onChange: jest.fn(), }; const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); const dropzone = container.querySelector("div"); fireEvent.click(dropzone); expect(rootProps.onClick).not.toHaveBeenCalled(); fireEvent.focus(dropzone); fireEvent.keyDown(dropzone); expect(rootProps.onFocus).not.toHaveBeenCalled(); expect(rootProps.onKeyDown).not.toHaveBeenCalled(); fireEvent.blur(dropzone); expect(rootProps.onBlur).not.toHaveBeenCalled(); await act(() => fireEvent.dragEnter(dropzone, event)); expect(rootProps.onDragEnter).not.toHaveBeenCalled(); fireEvent.dragOver(dropzone, event); expect(rootProps.onDragOver).not.toHaveBeenCalled(); fireEvent.dragLeave(dropzone, event); expect(rootProps.onDragLeave).not.toHaveBeenCalled(); await act(() => fireEvent.drop(dropzone, event)); expect(rootProps.onDrop).not.toHaveBeenCalled(); const input = container.querySelector("input"); fireEvent.click(input); expect(inputProps.onClick).not.toHaveBeenCalled(); await act(() => fireEvent.change(input)); expect(inputProps.onChange).not.toHaveBeenCalled(); }); test("{rootRef, inputRef} are exposed", () => { const { result } = renderHook(() => useDropzone()); const { rootRef, inputRef, getRootProps, getInputProps } = result.current; const { container } = render(
); expect(container.querySelector("div")).toEqual(rootRef.current); expect(container.querySelector("input")).toEqual(inputRef.current); }); test(" exposes and sets the ref if using a ref object", () => { const dropzoneRef = createRef(); const onClickSpy = jest.spyOn(HTMLInputElement.prototype, "click"); const ui = ( {({ getRootProps, getInputProps, isFocused }) => (
{isFocused &&
}
)} ); const { rerender } = render(ui); expect(dropzoneRef.current).not.toBeNull(); expect(typeof dropzoneRef.current.open).toEqual("function"); act(() => dropzoneRef.current.open()); expect(onClickSpy).toHaveBeenCalled(); rerender(null); expect(dropzoneRef.current).toBeNull(); }); test(" exposes and sets the ref if using a ref fn", () => { let dropzoneRef; const setRef = (ref) => (dropzoneRef = ref); const onClickSpy = jest.spyOn(HTMLInputElement.prototype, "click"); const ui = ( {({ getRootProps, getInputProps, isFocused }) => (
{isFocused &&
}
)} ); const { rerender } = render(ui); expect(dropzoneRef).not.toBeNull(); expect(typeof dropzoneRef.open).toEqual("function"); act(() => dropzoneRef.open()); expect(onClickSpy).toHaveBeenCalled(); rerender(null); expect(dropzoneRef).toBeNull(); }); test(" doesn't invoke the ref fn if it hasn't changed", () => { const setRef = jest.fn(); const { rerender } = render( {({ getRootProps, getInputProps }) => (
)}
); rerender( {({ getRootProps }) =>
} ); expect(setRef).toHaveBeenCalledTimes(1); }); it("sets {isFocused} to false if {disabled} is true", () => { const { container, rerender } = render( {({ getRootProps, getInputProps, isFocused }) => (
{isFocused &&
}
)} ); const dropzone = container.querySelector("div"); fireEvent.focus(dropzone); expect(dropzone.querySelector("#focus")).not.toBeNull(); rerender( {({ getRootProps, getInputProps, isFocused }) => (
{isFocused &&
}
)} ); expect(dropzone.querySelector("#focus")).toBeNull(); }); test("{tabindex} is 0 if {disabled} is false", () => { const { container } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("div")).toHaveAttribute("tabindex", "0"); }); test("{tabindex} is not set if {disabled} is true", () => { const { container, rerender } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("div")).toHaveAttribute("tabindex", "0"); rerender( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("div")).not.toHaveAttribute("tabindex"); }); test("{tabindex} is not set if {noKeyboard} is true", () => { const { container, rerender } = render( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("div")).toHaveAttribute("tabindex", "0"); rerender( {({ getRootProps, getInputProps }) => (
)}
); expect(container.querySelector("div")).not.toHaveAttribute("tabindex"); }); test("refs are set when {refKey} is set to a different value", (done) => { const data = createDtWithFiles(files); class MyView extends React.Component { render() { const { children, innerRef, ...rest } = this.props; return (
{children}
); } } const ui = ( {({ getRootProps }) => ( Drop some files here ... )} ); const { container, rerender } = render(ui); const dropzone = container.querySelector("#dropzone"); const fn = async () => { await act(() => fireEvent.drop(dropzone, data)); rerender(ui); done(); }; expect(fn).not.toThrow(); }); test("click events originating from