@atlaskit/pragmatic-drag-and-drop-docs
Version:
This package holds the documentation for Pragmatic drag and drop in one place. It is not intended to be consumed directly by consumers. The package is used by other tools for sharing examples
154 lines (128 loc) • 5.84 kB
text/mdx
---
order: 1
title: Testing
description: Guidance on how to test your drag and drop experiences
---
import SectionMessage from '@atlaskit/section-message';
`jsdom` does not implement [`DragEvent`](https://github.com/jsdom/jsdom/issues/2913) or `DOMRect`.
We have created a
[`DragEvent` and `DOMRect` polyfills](/components/pragmatic-drag-and-drop/optional-packages/unit-testing)
which implement `DragEvent` and `DOMRect` for jsdom.
You can force `@atlaskit/pragmatic-drag-and-drop` to dispatch events by firing native drag events
| Event name | Description | Target (what element the event is dispatch on) |
| ------------- | ---------------------------------------------- | ---------------------------------------------- |
| `"drag"` | A drag is occurring (_throttled_) | `draggable` element |
| `"dragend"` | A drag is finished | `draggable` element |
| `"dragenter"` | A drag is entering into an element | The `Element` being entered |
| `"dragleave"` | A drag is leaving into an element | The `Element` being left |
| `"dragover"` | A drag is occuring over a valid _drop target_ | The _drop target_ Element |
| `"dragstart"` | A drag is starting | `draggable` element |
| `"drop"` | A user successfully dropped on a _drop target_ | A _drop target_ `Element` |
A few things to keep in mind:
- How we use native events to publish our own events might change in the future, so ideally you
don't want to be writing too many tests that rely on how we use native events. Ideally you want to
be relying on a small amount of browser testing.
- `onGenerateDragPreview` fires during `"dragstart"`
- `onDragStart` fires in the animation frame after `"dragstart"`
- Internally we do not
- Any event (eg `onDrop`) will flush any pending `onDragStart` event
- We don't use `"drag"` events due to a bug in firefox; we rely on `"dragover"`
- We apply some additional throttling to `"dragover"` so we only fire it at most once per frame
- We mostly ignore `"dragleave"` and `"drag"` events
<SectionMessage appearance="information">
`jsdom` [does not support](https://github.com/jsdom/jsdom/issues/2913) the `DragEvent` interface. As
a consequence,
[](https://testing-library.com/docs/dom-testing-library/api-events/#fireeventeventname)
passed as a second parameter of the `@testing-library/dom` `fireEvent` drag methods (e.g.
`dragStart`, `dragOver`...) might be ignored during the test execution. Please use our `DragEvent`
polyfill to avoid this issue.
</SectionMessage>
```ts
import { fireEvent } from '@testing-library/dom';
import {
draggable,
dropTargetForElements,
monitorForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import { appendToBody, getElements } from '../../_util';
afterEach(async () => {
// cleanup any pending drags
fireEvent.dragEnd(window);
// Optional: unwind the "honey pot fix"
// More details: https://www.youtube.com/watch?v=udE9qbFTeQg
fireEvent.pointerMove(window);
});
it('should execute callbacks in response to native events', () => {
const [A] = getElements();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(A),
draggable({
element: A,
onGenerateDragPreview: () => ordered.push('draggable:preview'),
onDragStart: () => ordered.push('draggable:start'),
onDrag: () => ordered.push('draggable:drag'),
onDrop: () => ordered.push('draggable:drop'),
onDropTargetChange: () => ordered.push('draggable:change'),
}),
dropTargetForElements({
element: A,
onGenerateDragPreview: () => ordered.push('dropTarget:preview'),
onDragStart: () => ordered.push('dropTarget:start'),
onDrag: () => ordered.push('dropTarget:drag'),
onDrop: () => ordered.push('dropTarget:drop'),
onDropTargetChange: () => ordered.push('dropTarget:change'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
}),
monitorForElements({
onGenerateDragPreview: () => ordered.push('monitor:preview'),
onDragStart: () => ordered.push('monitor:start'),
onDrag: () => ordered.push('monitor:drag'),
onDrop: () => ordered.push('monitor:drop'),
onDropTargetChange: () => ordered.push('monitor:change'),
}),
);
expect(ordered).toEqual([]);
// starting a lift, this will trigger the previews to be generated
fireEvent.dragStart(A);
expect(ordered).toEqual(['draggable:preview', 'dropTarget:preview', 'monitor:preview']);
ordered.length = 0;
// ticking forward an animation frame will complete the lift
// @ts-expect-error
requestAnimationFrame.step();
expect(ordered).toEqual(['draggable:start', 'dropTarget:start', 'monitor:start']);
ordered.length = 0;
// [A] -> []
fireEvent.dragEnter(document.body);
expect(ordered).toEqual([
'draggable:change',
'dropTarget:change',
'dropTarget:leave',
'monitor:change',
]);
ordered.length = 0;
// [] -> [A]
fireEvent.dragEnter(A);
expect(ordered).toEqual([
'draggable:change',
'dropTarget:change',
'dropTarget:enter',
'monitor:change',
]);
ordered.length = 0;
// [A] -> [A]
fireEvent.dragOver(A, { clientX: 10 });
// no updates yet (need to wait for the next animation frame)
expect(ordered).toEqual([]);
// @ts-expect-error
requestAnimationFrame.step();
expect(ordered).toEqual(['draggable:drag', 'dropTarget:drag', 'monitor:drag']);
ordered.length = 0;
// drop
fireEvent.drop(A);
expect(ordered).toEqual(['draggable:drop', 'dropTarget:drop', 'monitor:drop']);
cleanup();
});
```