How to test react-draggable? Jest + Enzyme
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>
dragStart isn't a native browser event. You have to simulate an actual mouse click & drag.
@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).
Why not check this component's own tests? https://github.com/mzabriskie/react-draggable/blob/master/specs/draggable.spec.jsx#L173
@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.
Sorry - I'm unsure. If you come to a solution let me know.
@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.
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. :)
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.
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?