react-draggable icon indicating copy to clipboard operation
react-draggable copied to clipboard

How to test react-draggable? Jest + Enzyme

Open Artimal opened this issue 7 years ago • 9 comments

Hello, How to test react-draggable? I try to do it by following code but it is not working (spy is not called):

describe('<MyComponent /> component:', () => {
    let wrapper;
	const props = {
		dragStart: jest.fn(),
		dragExit: jest.fn(),
		dragMove: jest.fn()
	};

	beforeEach(() => {
		wrapper = shallow(<MyComponent {...props}/>);
	});

	describe('Interaction:', () => {
		it('should call dragStart()', () => {
			wrapper.find('Dragabble').simulate('dragStart');
			expect(props.dragStart).toHaveBeenCalled(); // FAIL
		});
		it('should call dragExit()', () => {
			wrapper.find('div.bar').simulate('dragExit');
			expect(props.dragExit).toHaveBeenCalled(); // FAIL
		});
	});	
});

My draggable component looks like this:

<Draggable
onStart={this.props.dragStart.bind(this)}
onStop={this.props.dragExit.bind(this)}
onDrag={this.props.dragMove.bind(this)}>
(...)
</Draggable>

Artimal avatar Jan 11 '18 16:01 Artimal

dragStart isn't a native browser event. You have to simulate an actual mouse click & drag.

STRML avatar Jan 11 '18 16:01 STRML

@STRML It also do not work with "click", "mouseDown", "mouseUp" simulated on parent, Draggable, child and also with expecting in 2 ways: expect(wrapper.instance().props.dragStart) and expect(props.dragStart).

Artimal avatar Jan 11 '18 17:01 Artimal

Why not check this component's own tests? https://github.com/mzabriskie/react-draggable/blob/master/specs/draggable.spec.jsx#L173

STRML avatar Jan 11 '18 17:01 STRML

@STRML When I use mount it works for dragStart and dragExit, but not for dragMove. I have tried many options combining mouseDown, mouseMove, mouseUp and with passing PageY: 0/PageY: 100 like .simulate('mouseMove', {PageY: 100}) but no one of that works.

Artimal avatar Jan 11 '18 19:01 Artimal

Sorry - I'm unsure. If you come to a solution let me know.

STRML avatar Jan 11 '18 20:01 STRML

@Artimal If you are passing the event name as a string then I think you have to use mousedown, mousemove and mouseup (lowercase).

That is what you pass into addEventListener anyway.

cstro avatar Jan 24 '18 12:01 cstro

For the lazy. I implemented a solution based on the tests link @STRML provided.

These are my current methods I pass as props for the Draggable (onDragStop ommited for brevity):

onDragStart() {
  this.setState({ dragging: true });
}

onDrag(e, data) {
  if (this.state.dragging) {
    this.setState({
      x: data.x,
      y: data.y
    });
  }
}

In my tests I implemented a function based on the tests example. It is very similar, with the difference I removed the code I don't need. Namely, the node.ownerDocument, because I have a single document on my environment.

function mouseMove(x, y, node) {
  const evt = document.createEvent('MouseEvents');
  evt.initMouseEvent("mousemove", true, true, window, 0, 0, 0, x, y, false, false, false, false, 0, null);
  document.dispatchEvent(evt);
  return evt;
}

To actually simulate a mouse move, you need to call this function more than once. So I did, in my tests:

expect(component.state().dragging).toBe(false);

expect(component.find("Draggable").at(1).prop("position")).toEqual({ x: 0, y: 0 });

component.find("Draggable").at(1).simulate("mousedown");

expect(component.state().dragging).toBe(true);

mouseMove(115, 319);
mouseMove(214, 325);
mouseMove(225, 356);
mouseMove(255, 375);

expect(component.find("Draggable").at(1).prop("position")).toEqual({ x: 140, y: 56 });

And...

 PASS  src\components\liveStream\liveStream.test.jsx
 PASS  src\components\liveStream\mediaPlayer.test.jsx
 PASS  src\components\liveStream\containers\liveStream.test.jsx

Test Suites: 3 passed, 3 total
Tests:       30 passed, 30 total
Snapshots:   0 total
Time:        7.293s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

Tests pass perfectly. :)

andreyluiz avatar Apr 24 '18 12:04 andreyluiz

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Draggable from 'react-draggable';

describe('Draggable component', () => {
  it('should move the element when dragged', () => {
    const { getByTestId } = render(
      <Draggable>
        <div data-testid="test-element" />
      </Draggable>
    );

    const element = getByTestId('test-element');

    const initialPosition = element.style.transform;
    expect(initialPosition).toBeFalsy();

    const handle = getByTestId('test-element').querySelector('.react-draggable-handle');
    const initialX = handle.style.left;
    const initialY = handle.style.top;

    // simulate dragging
    fireEvent.mouseDown(handle, { clientX: 0, clientY: 0 });
    fireEvent.mouseMove(handle, { clientX: 100, clientY: 100 });
    fireEvent.mouseUp(handle);

    const newPosition = element.style.transform;
    expect(newPosition).toBeTruthy();

    const newX = handle.style.left;
    const newY = handle.style.top;
    expect(newX).not.toBe(initialX);
    expect(newY).not.toBe(initialY);
  });
});

In this example, we use the render, getByTestId, fireEvent.mouseDown, fireEvent.mouseMove, and fireEvent.mouseUp methods from the @testing-library/react library to simulate dragging. We also use the data-testid attribute to find the element in the DOM. The final assertion remains the same.

slisarenko avatar Apr 13 '23 09:04 slisarenko

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Draggable from 'react-draggable';

describe('Draggable component', () => {
  it('should move the element when dragged', () => {
    const { getByTestId } = render(
      <Draggable>
        <div data-testid="test-element" />
      </Draggable>
    );

    const element = getByTestId('test-element');

    const initialPosition = element.style.transform;
    expect(initialPosition).toBeFalsy();

    const handle = getByTestId('test-element').querySelector('.react-draggable-handle');
    const initialX = handle.style.left;
    const initialY = handle.style.top;

    // simulate dragging
    fireEvent.mouseDown(handle, { clientX: 0, clientY: 0 });
    fireEvent.mouseMove(handle, { clientX: 100, clientY: 100 });
    fireEvent.mouseUp(handle);

    const newPosition = element.style.transform;
    expect(newPosition).toBeTruthy();

    const newX = handle.style.left;
    const newY = handle.style.top;
    expect(newX).not.toBe(initialX);
    expect(newY).not.toBe(initialY);
  });
});

In this example, we use the render, getByTestId, fireEvent.mouseDown, fireEvent.mouseMove, and fireEvent.mouseUp methods from the @testing-library/react library to simulate dragging. We also use the data-testid attribute to find the element in the DOM. The final assertion remains the same.

Is there any solution you found out? How to use data-testid as attribute for the jest test code?

brijesh-imemori avatar Mar 12 '24 06:03 brijesh-imemori