React-testing-library: fireEvent.drop is not including event.dataTransfer

Created on 1 Apr 2019  ·  10Comments  ·  Source: testing-library/react-testing-library

  • react-testing-library version: 6.0.1
  • react version: 16.8.1
  • node version: 8.9.4
  • npm version: 5.6.0
  • jest version: 24.0.0

Relevant code or config:

Below is a simplified, generic version of my code

export const FileDropZone = props => {

    const handleDrop = useCallback(
        event => {
            event.stopPropagation();
            event.preventDefault();
            handleFiles(event.dataTransfer.files);
        },
        [handleFiles]
    );

    // Rest of code

    return (
        <div
            onDragEnter={handleDragEnter}
            onDragLeave={handleDragLeave}
            onDrop={handleDrop}
        >
            Drag File Here
        </div>
    );
}

describe('FileDropZone', () => {
    test('should handle a file being dropped in the drop zone', () => {
        const file = new File(['(⌐□_□)'], 'chucknorris.png', {
            type: 'image/png',
        })
        const {getByText, queryByText} = render(<FileDropZone {...props} />);
        expect(queryByText('chucknorris.png')).toBeNull();
        const dropZone = getByText('Drag File Here');
        act(() => {
            fireEvent.drop(dropZone, {dataTransfer: {files: [file]}});
        });
        expect(queryByText('chucknorris.png')).toBeInTheDocument();
    })
})

What you did:

I am trying to test a drop event that is used for uploading files via drag-and-drop

What happened:

When I run my unit test, the event is firing, but I get the following error

TypeError: Cannot read property 'files' of undefined

When I do a console.log of the event it shows that event.dataTransfer is undefined.

Reproduction:

Unable to provide a link to code repository due to the repo being private

Problem description:

Unable to test file upload via drag-and-drop using react-testing-library

help wanted jsdom needs investigation question

Most helpful comment

For anyone that finds their way to this ticket via a search whilst they are stuck on the same problem, I managed to work around the limitation in jsdom using Object.defineProperty like so:

const file = new File([""], "guybrushthreepwood.png", {
  type: "image/png",
}

const mockDropEvent = new window.Event("drop")
Object.defineProperty(event, "dataTransfer", {
  value: {
    files: [file]
  }
})

const target = getByText("Drag File Here")

fireEvent(target, mockDropEvent)

I'm not sure how evil this approach is, but it might come in handy :)

All 10 comments

Hi @christopher-schroer,

I'm not sure what this could be. Without a simple reproduction in a codesandbox there's only so much we can do.

@kentcdodds I figured as much. Once I have some free time, I will try to create a repo for sharing. Unfortunately, I'm going to be on vacation until Apr 11.

I managed to put together a basic example

https://github.com/christopher-schroer/react-testing-library-drop-issue

Clone it, run npm install, and then run npm test

Ah, this appears to be an issue with jsdom not supporting dataTransfer. Based on these tests.

You could file an issue against jsdom to see what it would take to contribute support for dataTransfer.

Closing this in favor of: https://github.com/jsdom/jsdom/issues/1568

Thanks.

For anyone that finds their way to this ticket via a search whilst they are stuck on the same problem, I managed to work around the limitation in jsdom using Object.defineProperty like so:

const file = new File([""], "guybrushthreepwood.png", {
  type: "image/png",
}

const mockDropEvent = new window.Event("drop")
Object.defineProperty(event, "dataTransfer", {
  value: {
    files: [file]
  }
})

const target = getByText("Drag File Here")

fireEvent(target, mockDropEvent)

I'm not sure how evil this approach is, but it might come in handy :)

Seems legit. Would be cool to get this added to the examples: https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples

@andypearson I wasn't able to get that exact code to work, but I got a very similar version working:

const fileDropzone = getByText('Drag and Drop Excel Files Here');
const fileDropEvent = createEvent.drop(fileDropzone);
const fileList = [file];

Object.defineProperty(fileDropEvent, 'dataTransfer', {
  value: {
    files: {
      item: itemIndex => fileList[itemIndex],
      length: fileList.length,
    },
  },
});

fireEvent(fileDropzone, fileDropEvent);

Key differences here:

I'm using the RTL createEvent to create the event. window.Event wasn't working for me.

Rather than return files: [file] I created the item property which mocks the FileItem object which has the item property that looks roughly like the function I defined for it. Using an actual FileItem object is a major headache, but if someone else wanted to look into it more here is a pretty in depth post that goes into it: https://github.com/jsdom/jsdom/issues/1272#issuecomment-486088445

@kentcdodds I'll see what I can do!

For anyone testing drag and drop and wants to test setData and the above two approach are not working
Using
const mockEv = new window.Event('dragstart') //Object.defineProperty ... fireEvent(draggableNode, mockEv)
doesn't fire event, resulting in handleDragStart() not being called

Second approach with using createEvent fires the desired event, but, Object.defineProperty(event, 'dataTransfer', { setData: jest.fn() }) doesn't actually defines the desired 'dataTransfer' property.

A quick workaround for me was to use Object.assign(event, {dataTransfer: {setData: jest.fn()}})

Full working example as of testing-library/[email protected]

`test('on drag start sets dataTransfer property correctly', () => {
const setData = jest.fn()
const ev = {
dataTransfer: {
setData
}
}
const {
getByTestId
} = render();

const draggableOpNode = getByTestId('ops-bucket-item');
const mockDropEvent = createEvent.dragStart(draggableOpNode);

Object.assign(mockDropEvent, ev);
fireEvent(draggableOpNode, mockDropEvent)

expect(setData).toHaveBeenCalledTimes(1)
expect(setData).toHaveBeenCalledWith({ /*your correct data*/ })`
Was this page helpful?
0 / 5 - 0 ratings