Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fireEvent.drop is not including event.dataTransfer #339

Closed
christopherschroer opened this issue Apr 1, 2019 · 10 comments
Closed

fireEvent.drop is not including event.dataTransfer #339

christopherschroer opened this issue Apr 1, 2019 · 10 comments
Labels
help wanted Extra attention is needed jsdom Issue with JSDOM environment needs investigation question Further information is requested

Comments

@christopherschroer
Copy link

  • 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

@kentcdodds
Copy link
Member

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 kentcdodds added help wanted Extra attention is needed question Further information is requested needs investigation labels Apr 1, 2019
@christopherschroer
Copy link
Author

@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.

@alexkrolick alexkrolick added the jsdom Issue with JSDOM environment label Apr 1, 2019
@christopherschroer
Copy link
Author

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

@kentcdodds
Copy link
Member

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.

@kentcdodds
Copy link
Member

Closing this in favor of: jsdom/jsdom#1568

Thanks.

@andypearson
Copy link

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 :)

@kentcdodds
Copy link
Member

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

@JordanBourne
Copy link

JordanBourne commented Aug 29, 2019

@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: jsdom/jsdom#1272 (comment)

@andypearson
Copy link

@kentcdodds I'll see what I can do!

@ishanshukla97
Copy link

ishanshukla97 commented May 11, 2020

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/react@10.0.4

`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*/ })`

lucbpz pushed a commit to lucbpz/react-testing-library that referenced this issue Jul 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed jsdom Issue with JSDOM environment needs investigation question Further information is requested
Projects
None yet
Development

No branches or pull requests

6 participants