This is how I have personally achieved that:
import { act, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
describe('My Slider', () => {
const mockOnRangeChange = jest.fn()
let user
beforeEach(() => {
jest
.spyOn(window.HTMLElement.prototype, 'getBoundingClientRect')
.mockImplementation(() => ({
width: 140,
left: 0,
right: 140,
height: 28,
top: 0,
bottom: 28
}))
user = userEvent.setup()
render(
<MySlider
min={2}
max={16}
defaultRange={[6, 8]}
onRangeChange={mockOnRangeChange}
/>
)
})
afterEach(() => {
jest.restoreAllMocks()
})
it('renders a range slider with the given limits and initial values', () => {
const sliderHandles = screen.getAllByRole('slider')
expect(sliderHandles).toHaveLength(2)
sliderHandles.forEach((slider) => {
expect(slider).toHaveAttribute('aria-valuemin', '2')
expect(slider).toHaveAttribute('aria-valuemax', '16')
})
expect(sliderHandles[0]).toHaveAttribute('aria-valuenow', '6')
expect(sliderHandles[0]).toHaveAttribute('aria-label', 'My slider - Minimum')
expect(sliderHandles[1]).toHaveAttribute('aria-valuenow', '8')
expect(sliderHandles[1]).toHaveAttribute('aria-label', 'My Slider - maximum')
})
describe('when the range changes', () => {
it("calls 'onRangeChange' callback with the current range", async () => {
const sliderHandles = screen.getAllByRole('slider')
await act(async () => {
await user.pointer([
{ target: sliderHandles[0], keys: '[MouseLeft>]' },
{ coords: { pageX: 10 } },
{ keys: '[/MouseLeft]' }
])
})
expect(mockOnRangeChange).toHaveBeenLastCalledWith([7, 8])
await act(async () => {
await user.pointer([
{ target: sliderHandles[1], keys: '[MouseLeft>]' },
{ coords: { pageX: 40 } },
{ keys: '[/MouseLeft]' }
])
})
expect(mockOnRangeChange).toHaveBeenLastCalledWith([7, 11])
})
})
})
Basically the getBoundingClientRect function must be globally mocked and then restored at the end of the test. This is necessary in JSDOM, as rendered components don't have real dimensions and, therefore, dragging an handle in any direction cannot trigger any meaningful change of value (apart from selecting the minimum or the maximum value).
I am using the slider widget from react-component/slider in JSDOM.