-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Add docs on testing #623
Comments
If somebody is keen to pick this up please let me know first to avoid multiple people working on it at the same time 👍 |
@kentcdodds I thought you might know somebody who would be interested in giving this a crack! |
I'd recommend that you actually publish a module that mocks out the API. This way people can contribute and make it better and better :) |
Can you elaborate a little more? |
Or do you have any examples of this? |
@alexreardon I am happy to spend some time on it. Currently how do you unit test react-beautiful-dnd wrapped components? Currently if I do snapshot testing I get <Connect(Draggable)
disableInteractiveElementBlocking={false}
draggableId="id"
index={0}
isDragDisabled={true}
>
<Component />
</Connect(Draggable)> instead of the Component itself. Additionally, I would love to override some props like (isDragging) and snapshot that as well |
Feel free to give it a crack @huchenme ! |
It does not seems like a "good first issue" to me at the moment, looks a bit challenging. Can I have some guides or a list of TODO items? (files I might need to look at / other repositories etc.) |
I have figured out a way to test a draggable: const component = shallow(<YourComponentWithDraggableInside />);
const draggable = component.find('Connect(Draggable)').first();
const inner = shallow(
draggable.prop('children')(/* you can put provided and snapshot here */)
).find('YourInnerComponentName');
expect(inner).toMatchSnapshot(); |
@alexreardon I agree with @huchenme that this does not seem like the perfect first issue :) Could you at least provide some ideas on how you test dragging when using this component? I.e. can you cut and paste some code that shows how you simulate the events needed to drag an element from one draggable and to another (or to an empty one?). From there it is possible to see how to write tests that tests the testes code's interaction with the library. Regards, |
Hi again. Some thoughts regarding test strategies and -requirements for testing something that implements RBD. I've been converting old tests from react-dnd today and
Thus I feel that what is needed is a small set of helpers that ensure that For a) some simple helpers might be enough - something like For b) maybe a context above the DragDropContext that could be used to trigger different phases and drop points. Something like:
|
I ended up with this:
|
OK, heres an updated version that also handles nested droppables. Example usage : const page = mount(<MyComponent {...props} />)
simulateDragAndDrop(page, 123, 1, 134, 0)
// do asserts here /* eslint-env jest */
import React from 'react'
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'
export function withDndContext(element) {
return <DragDropContext>{element}</DragDropContext>
}
function makeDroppableInfo(droppable) {
const { droppableId } = droppable.props()
// console.log('droppableId', droppableId)
return {
droppableId,
draggables: {},
draggableIds: [],
}
}
function makeDraggableInfo(draggable) {
const { draggableId, index, type } = draggable.props()
const droppable = draggable.closest(Droppable)
if (droppable.length === 0) {
throw new Error(`No Droppable found for draggable: ${draggableId}`)
}
const { droppableId } = droppable.props()
// console.log('draggableId', droppableId, draggableId)
const draggableInfo = {
droppableId,
draggableId,
index,
type,
}
return draggableInfo
}
export function buildRegistry(page) {
const registry = {
droppables: {},
droppableIds: [],
}
page.find(Droppable).forEach(droppable => {
const droppableInfo = makeDroppableInfo(droppable)
registry.droppableIds.push(droppableInfo.droppableId)
registry.droppables[droppableInfo.droppableId] = droppableInfo
})
page.find(Draggable).forEach(draggable => {
const draggableInfo = makeDraggableInfo(draggable)
const { droppableId } = draggableInfo
registry.droppables[droppableId].draggables[
draggableInfo.draggableId
] = draggableInfo
registry.droppables[droppableId].draggableIds.push(
draggableInfo.draggableId
)
})
return registry
}
export function simulateDragAndDrop(
page,
fromDroppableId,
draggableIndex,
toDroppableId,
toIndex
) {
const reg = buildRegistry(page)
if (
reg.droppableIds.indexOf(fromDroppableId) == -1 ||
reg.droppableIds.indexOf(toDroppableId) == -1
) {
throw new Error(
`One of the droppableIds missing in page. Only found these ids: ${reg.droppableIds.join(
', '
)}`
)
}
if (!reg.droppables[fromDroppableId].draggableIds[draggableIndex]) {
throw new Error(`No element found in index ${draggableIndex}`)
}
const draggableId =
reg.droppables[fromDroppableId].draggableIds[draggableIndex]
const draggable = reg.droppables[fromDroppableId].draggables[draggableId]
if (!draggable) {
throw new Error(
`No draggable fond for ${draggableId} in fromDroppablas which contain ids : ${Object.keys(
reg.droppables[fromDroppableId].draggables
).join(', ')}`
)
}
if (typeof draggableId === 'undefined') {
throw new Error(
`No draggable found on fromIndex nr ${draggableIndex} index contents:[${reg.droppables[
fromDroppableId
].draggableIds.join(', ')}] `
)
}
const dropResult = {
draggableId,
type: draggable.type,
source: { index: draggableIndex, droppableId: fromDroppableId },
destination: { droppableId: toDroppableId, index: toIndex },
reason: 'DROP',
}
// yes this is very much against all testing priciples.
// but it is the best we can do for now :)
page
.find(DragDropContext)
.props()
.onDragEnd(dropResult)
} |
👋 folks. If you're using |
Love this. Can @colinrcummings can you add a PR to include this in the community section? |
Also, this might get a bit easier with our #162 api |
Wrote a few utils for simpler testing, thought I'd share since The idea is to test without having to know the current order. verticalDrag(thisElement).inFrontOf(thatElement) Currently doesn't support dragging between lists. |
Posting my journey to test RBD components in case it's useful. Rather than testing what happens in my app when drag operations occur, I've been figuring out how to test the other features of my components that are wrapped in DnD.Draggable. If there's going to be comprehensive testing documentation, it would be great to cover both. My initial solution works like this: test('renders a Block for each data item', t => {
const wrapper = shallow(<Editor load_state={State.Loaded} blocks={test_blocks} data={test_data} />);
const drop_wrapper = wrapper.find('Connect(Droppable)');
const drop_inner = shallow(drop_wrapper.prop('children')(
{
innerRef: '',
droppableProps: [ ],
},
null
));
t.is(test_data.length, drop_inner.at(0).children().length);
}); Here's the relevant app code: <DnD.DragDropContext onDragEnd={this.cb_reorder}>
<DnD.Droppable droppableId="d-blocks" type="block">{(prov, snap) => (
<div ref={prov.innerRef} {...prov.droppableProps}>
{data.map((data_item, index) => (
<DnD.Draggable key={`block-${data_item.uid}`} draggableId={`block-${data_item.uid}`} index={index} type="block">{(prov, snap) => (
<div className="block-list-item" ref={prov.innerRef} {...prov.draggableProps} {...prov.dragHandleProps} style={block_drag_styles(snap, prov)}>
<Block data_item={data_item} index={index} />
</div>
)}</DnD.Draggable>
))}
{prov.placeholder}
</div>
)}</DnD.Droppable>
</DnD.DragDropContext> I was helped by @huchenme's comment above. I also tried stubbing the relevant components using sinon, but I did not manage to get this to work. A resource explaining if / how stubbing the RBD components is possible would be valuable. I eventually settled on a simpler approach, because the above can get very for more complex, multiply nested components. I modified the app component to accept mock components as props for DnD.Draggable and ContextConsumer. function Block(props) {
const DraggableComponent = props.draggable_component || DnD.Draggable;
const ContextConsumer = props.consumer_component || MyDataContext;
const FieldRenderer = props.field_renderer_component || RecursiveFieldRenderer;
...
return (
<DraggableComponent ...>{(prov, snap) => (
...
<ContextConsumer>((ctx) => (
<FieldRenderer />
</ContextConsumer>
...
</DraggableComponent>
);
} With a helper to create mock elements, tests are very concise, and much less fragile than the other methods I've tried to test components wrapped in RBD. function func_stub(child_args) {
return function ChildFunctionStub(props) {
return (
<div>
{props.children(...child_args)}
</div>
);
};
}
function Stub(props) {
return (
<div>
{props.children}
</div>
);
}
function mk_stubbed_block(data_item, blocks) {
return mount(<Block data_item={data_item} index={0}
draggable_component={func_stub([provided, snapshot])}
consumer_component={func_stub([{ blocks }])}
field_renderer_component={Stub} />);
}
test('Block: warning if invalid block type', t => {
const wrapper = mk_stubbed_block(test_data[0], [ ]);
const exp = <h3 className='title is-4'>Warning: invalid block</h3>;
t.is(true, wrapper.contains(exp));
}); Thanks! |
Love react beautiful dnd! However i'm still finding very little to no documentation testing the drag itself. Seeing this post as a bit old now, anyone have a working example? @mik3u @colinrobertbrooks i've tried both your test util's but did not get it working (tester and test-utils), i wonder if it's just outdated with the newest RBD version or maybe i've done something wrong. My draggable list isn't keyboard accessible at the moment and wonder if that may be the culprit of it not working with your solutions.. I have come across another solution that doesn't look to be included on this thread for anyone that may go this route Didn't work for me while testing RBD but maybe it will for others. Will update here if something does end up working! |
@daanishnasir, |
We are looking to create a markdown file which contains some common testing patterns. Specific focus is around mocking or stubbing out the react-beautiful-dnd components behaviour so that consumers can focus on their own logic
The text was updated successfully, but these errors were encountered: