Does not work with UserEvent v14
UserEvent v14 introduced a couple of breaking changes that have broken compatibility with this library.
- All userEvents now return promises that must be awaited/resolved
- The "{space}" key code has been removed in favor of "[Space]" or " "
The lint rules for testing-library are also out of date, but I think that's on another one of your projects.
If anyone's looking for a solution on how to drag and drop with the latest react, jest and react testing library, here are my utils that do work:
import { act, fireEvent, screen } from '@testing-library/react'
enum Keys {
SPACE = 32,
ARROW_LEFT = 37,
ARROW_UP = 38,
ARROW_RIGHT = 39,
ARROW_DOWN = 40,
}
export enum DragDirection {
LEFT = Keys.ARROW_LEFT,
UP = Keys.ARROW_UP,
RIGHT = Keys.ARROW_RIGHT,
DOWN = Keys.ARROW_DOWN,
}
// taken from https://github.com/hello-pangea/dnd/blob/main/test/unit/integration/util/controls.ts#L20
const createTransitionEndEvent = (): Event => {
const event = new Event('transitionend', {
bubbles: true,
cancelable: true,
}) as TransitionEvent
// cheating and adding property to event as
// TransitionEvent constructor does not exist.
// This is needed because of the following check
// https://github.com/atlassian/react-beautiful-dnd/blob/master/src/view/draggable/draggable.jsx#L130
// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(event as any).propertyName = 'transform'
return event
}
export const pickUp = async (element: HTMLElement) => {
fireEvent.keyDown(element, {
keyCode: Keys.SPACE,
})
await screen.findByText(/You have lifted an item/i)
await act(() => {
jest.runOnlyPendingTimers()
})
}
export const move = async (element: HTMLElement, direction: DragDirection) => {
fireEvent.keyDown(element, {
keyCode: direction,
})
await screen.findByText(/(You have moved the item | has been combined with)/i)
}
export const drop = async (element: HTMLElement) => {
fireEvent.keyDown(element, {
keyCode: Keys.SPACE,
})
fireEvent(element, createTransitionEndEvent())
await screen.findByText(/You have dropped the item/i)
}
Notes:
- I have both
provided.draggablePropsandprovided.dragHandlePropsspread on the sameelement(the same one which I am passing to the util functions).TransitionEndevent must be fired on the element which hasprovided.draggablePropsspreaded on. - This requires
jest.useFakeTimers({ advanceTimers: true })(in my caseadvanceTimersis required otherwise it hangs, i haven't checked whether it's because of the drag and drop library or something in my code). This is not strictly necessary, theactblock can be removed but then anot wrapped in acterror comes up with the source beingTransitionGroup. - It only works when moving items up/down because there's no bounding client rect in jsdom.
If anyone's looking for a solution on how to drag and drop with the latest react, jest and react testing library, here are my utils that do work:
import { act, fireEvent, screen } from '@testing-library/react' enum Keys { SPACE = 32, ARROW_LEFT = 37, ARROW_UP = 38, ARROW_RIGHT = 39, ARROW_DOWN = 40, } export enum DragDirection { LEFT = Keys.ARROW_LEFT, UP = Keys.ARROW_UP, RIGHT = Keys.ARROW_RIGHT, DOWN = Keys.ARROW_DOWN, } // taken from https://github.com/hello-pangea/dnd/blob/main/test/unit/integration/util/controls.ts#L20 const createTransitionEndEvent = (): Event => { const event = new Event('transitionend', { bubbles: true, cancelable: true, }) as TransitionEvent // cheating and adding property to event as // TransitionEvent constructor does not exist. // This is needed because of the following check // https://github.com/atlassian/react-beautiful-dnd/blob/master/src/view/draggable/draggable.jsx#L130 // eslint-disable-next-line @typescript-eslint/no-explicit-any ;(event as any).propertyName = 'transform' return event } export const pickUp = async (element: HTMLElement) => { fireEvent.keyDown(element, { keyCode: Keys.SPACE, }) await screen.findByText(/You have lifted an item/i) await act(() => { jest.runOnlyPendingTimers() }) } export const move = async (element: HTMLElement, direction: DragDirection) => { fireEvent.keyDown(element, { keyCode: direction, }) await screen.findByText(/(You have moved the item | has been combined with)/i) } export const drop = async (element: HTMLElement) => { fireEvent.keyDown(element, { keyCode: Keys.SPACE, }) fireEvent(element, createTransitionEndEvent()) await screen.findByText(/You have dropped the item/i) }Notes:
- I have both
provided.draggablePropsandprovided.dragHandlePropsspread on the sameelement(the same one which I am passing to the util functions).TransitionEndevent must be fired on the element which hasprovided.draggablePropsspreaded on.- This requires
jest.useFakeTimers({ advanceTimers: true })(in my caseadvanceTimersis required otherwise it hangs, i haven't checked whether it's because of the drag and drop library or something in my code). This is not strictly necessary, theactblock can be removed but then anot wrapped in acterror comes up with the source beingTransitionGroup.- It only works when moving items up/down because there's no bounding client rect in jsdom.
Used this with user events 14 today to test a drag & drop menu, we removed the await from the act because it was generating a warning or error. But thanks for posting this!
How does one use the provided code? Does it replace this library?
How does one use the provided code? Does it replace this library?
Yes it does replace this library, though it's been a while and I can't tell you whether it still works with the latest versions of the libraries mentioned in my original comment.
@saltenasl Thank you so much for sharing your utility methods (https://github.com/colinrobertbrooks/react-beautiful-dnd-test-utils/issues/18#issuecomment-1373388693)
Amazing <3