1313 lines
42 KiB
TypeScript
1313 lines
42 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License
|
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
* 2.0.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { render, mount, ReactWrapper } from 'enzyme';
|
|
import { DragDrop } from './drag_drop';
|
|
import {
|
|
ChildDragDropProvider,
|
|
DragContextState,
|
|
ReorderProvider,
|
|
DragDropIdentifier,
|
|
DraggingIdentifier,
|
|
DropIdentifier,
|
|
} from './providers';
|
|
import { act } from 'react-dom/test-utils';
|
|
import { DropType } from '../types';
|
|
|
|
jest.useFakeTimers();
|
|
|
|
const dataTransfer = {
|
|
setData: jest.fn(),
|
|
getData: jest.fn(),
|
|
};
|
|
|
|
describe('DragDrop', () => {
|
|
const defaultContext = {
|
|
dragging: undefined,
|
|
setDragging: jest.fn(),
|
|
setActiveDropTarget: jest.fn(),
|
|
activeDropTarget: undefined,
|
|
dropTargetsByOrder: undefined,
|
|
keyboardMode: false,
|
|
setKeyboardMode: () => {},
|
|
setA11yMessage: jest.fn(),
|
|
registerDropTarget: jest.fn(),
|
|
};
|
|
|
|
const value = {
|
|
id: '1',
|
|
humanData: { label: 'hello', groupLabel: 'X', position: 1, canSwap: true, canDuplicate: true },
|
|
};
|
|
|
|
test('renders if nothing is being dragged', () => {
|
|
const component = render(
|
|
<DragDrop value={value} draggable order={[2, 0, 1, 0]}>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
);
|
|
|
|
expect(component).toMatchSnapshot();
|
|
});
|
|
|
|
test('dragover calls preventDefault if dropType is defined', () => {
|
|
const preventDefault = jest.fn();
|
|
const component = mount(
|
|
<DragDrop dropTypes={['field_add']} value={value} order={[2, 0, 1, 0]}>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
);
|
|
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(0).simulate('dragover', { preventDefault });
|
|
|
|
expect(preventDefault).toBeCalled();
|
|
});
|
|
|
|
test('dragover does not call preventDefault if dropTypes is undefined', () => {
|
|
const preventDefault = jest.fn();
|
|
const component = mount(
|
|
<DragDrop value={value} order={[2, 0, 1, 0]}>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
);
|
|
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(0).simulate('dragover', { preventDefault });
|
|
|
|
expect(preventDefault).not.toBeCalled();
|
|
});
|
|
|
|
test('removes selection on mouse down before dragging', async () => {
|
|
const removeAllRanges = jest.fn();
|
|
global.getSelection = jest.fn(() => (({ removeAllRanges } as unknown) as Selection));
|
|
const component = mount(
|
|
<DragDrop value={value} draggable={true} order={[2, 0, 1, 0]}>
|
|
<button>Hi!</button>
|
|
</DragDrop>
|
|
);
|
|
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(0).simulate('mousedown');
|
|
expect(global.getSelection).toBeCalled();
|
|
expect(removeAllRanges).toBeCalled();
|
|
});
|
|
|
|
test('dragstart sets dragging in the context and calls it with proper params', async () => {
|
|
const setDragging = jest.fn();
|
|
|
|
const setA11yMessage = jest.fn();
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...defaultContext}
|
|
dragging={undefined}
|
|
setDragging={setDragging}
|
|
setA11yMessage={setA11yMessage}
|
|
>
|
|
<DragDrop value={value} draggable={true} order={[2, 0, 1, 0]}>
|
|
<button>Hi!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(0).simulate('dragstart', { dataTransfer });
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
expect(dataTransfer.setData).toBeCalledWith('text', 'hello');
|
|
expect(setDragging).toBeCalledWith({ ...value });
|
|
expect(setA11yMessage).toBeCalledWith('Lifted hello');
|
|
});
|
|
|
|
test('drop resets all the things', async () => {
|
|
const preventDefault = jest.fn();
|
|
const stopPropagation = jest.fn();
|
|
const setDragging = jest.fn();
|
|
const onDrop = jest.fn();
|
|
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...defaultContext}
|
|
dragging={{ id: '2', humanData: { label: 'Label1' } }}
|
|
setDragging={setDragging}
|
|
>
|
|
<DragDrop onDrop={onDrop} dropTypes={['field_add']} value={value} order={[2, 0, 1, 0]}>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
const dragDrop = component.find('[data-test-subj="lnsDragDrop"]').at(0);
|
|
dragDrop.simulate('dragOver');
|
|
dragDrop.simulate('drop', { preventDefault, stopPropagation });
|
|
|
|
expect(preventDefault).toBeCalled();
|
|
expect(stopPropagation).toBeCalled();
|
|
expect(setDragging).toBeCalledWith(undefined);
|
|
expect(onDrop).toBeCalledWith({ id: '2', humanData: { label: 'Label1' } }, 'field_add');
|
|
});
|
|
|
|
test('drop function is not called on dropTypes undefined', async () => {
|
|
const preventDefault = jest.fn();
|
|
const stopPropagation = jest.fn();
|
|
const setDragging = jest.fn();
|
|
const onDrop = jest.fn();
|
|
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...defaultContext}
|
|
dragging={{ id: 'hi', humanData: { label: 'Label1' } }}
|
|
setDragging={setDragging}
|
|
>
|
|
<DragDrop onDrop={onDrop} dropTypes={undefined} value={value} order={[2, 0, 1, 0]}>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
const dragDrop = component.find('[data-test-subj="lnsDragDrop"]').at(0);
|
|
dragDrop.simulate('dragover');
|
|
dragDrop.simulate('drop', { preventDefault, stopPropagation });
|
|
|
|
expect(preventDefault).not.toHaveBeenCalled();
|
|
expect(stopPropagation).not.toHaveBeenCalled();
|
|
expect(setDragging).not.toHaveBeenCalled();
|
|
expect(onDrop).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('defined dropTypes is reflected in the className', () => {
|
|
const component = render(
|
|
<DragDrop
|
|
onDrop={(x: unknown) => {
|
|
throw x;
|
|
}}
|
|
dropTypes={['field_add']}
|
|
value={value}
|
|
order={[2, 0, 1, 0]}
|
|
>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
);
|
|
|
|
expect(component).toMatchSnapshot();
|
|
});
|
|
|
|
test('items that has dropTypes=undefined get special styling when another item is dragged', () => {
|
|
const component = mount(
|
|
<ChildDragDropProvider {...defaultContext} dragging={{ ...value }}>
|
|
<DragDrop value={value} draggable={true} order={[2, 0, 1, 0]}>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
<DragDrop
|
|
order={[2, 0, 1, 0]}
|
|
onDrop={(x: unknown) => {}}
|
|
dropTypes={undefined}
|
|
value={{ id: '2', humanData: { label: 'label2' } }}
|
|
>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
expect(component.find('[data-test-subj="lnsDragDrop"]').at(1)).toMatchSnapshot();
|
|
});
|
|
|
|
test('additional styles are reflected in the className until drop', () => {
|
|
let dragging: { id: '1'; humanData: { label: 'Label1' } } | undefined;
|
|
const getAdditionalClassesOnEnter = jest.fn().mockReturnValue('additional');
|
|
const getAdditionalClassesOnDroppable = jest.fn().mockReturnValue('droppable');
|
|
const setA11yMessage = jest.fn();
|
|
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...defaultContext}
|
|
dragging={dragging}
|
|
setA11yMessage={setA11yMessage}
|
|
setDragging={() => {
|
|
dragging = { id: '1', humanData: { label: 'Label1' } };
|
|
}}
|
|
>
|
|
<DragDrop
|
|
value={{ id: '3', humanData: { label: 'ignored' } }}
|
|
draggable={true}
|
|
order={[2, 0, 1, 0]}
|
|
>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
<DragDrop
|
|
order={[2, 0, 1, 0]}
|
|
value={value}
|
|
onDrop={(x: unknown) => {}}
|
|
dropTypes={['field_add']}
|
|
getAdditionalClassesOnEnter={getAdditionalClassesOnEnter}
|
|
getAdditionalClassesOnDroppable={getAdditionalClassesOnDroppable}
|
|
>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
expect(setA11yMessage).toBeCalledWith('Lifted ignored');
|
|
|
|
const dragDrop = component.find('[data-test-subj="lnsDragDrop"]').at(1);
|
|
dragDrop.simulate('dragOver');
|
|
dragDrop.simulate('drop');
|
|
expect(component.find('.additional')).toHaveLength(0);
|
|
});
|
|
|
|
test('additional enter styles are reflected in the className until dragleave', () => {
|
|
let dragging: { id: '1'; humanData: { label: 'Label1' } } | undefined;
|
|
const getAdditionalClasses = jest.fn().mockReturnValue('additional');
|
|
const getAdditionalClassesOnDroppable = jest.fn().mockReturnValue('droppable');
|
|
const setActiveDropTarget = jest.fn();
|
|
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
setA11yMessage={jest.fn()}
|
|
dragging={dragging}
|
|
setDragging={() => {
|
|
dragging = { id: '1', humanData: { label: 'Label1' } };
|
|
}}
|
|
setActiveDropTarget={setActiveDropTarget}
|
|
activeDropTarget={value as DragContextState['activeDropTarget']}
|
|
keyboardMode={false}
|
|
setKeyboardMode={(keyboardMode) => true}
|
|
dropTargetsByOrder={undefined}
|
|
registerDropTarget={jest.fn()}
|
|
>
|
|
<DragDrop
|
|
value={{ id: '3', humanData: { label: 'ignored' } }}
|
|
draggable={true}
|
|
order={[2, 0, 1, 0]}
|
|
>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
<DragDrop
|
|
order={[2, 0, 1, 0]}
|
|
value={value}
|
|
onDrop={(x: unknown) => {}}
|
|
dropTypes={['field_add']}
|
|
getAdditionalClassesOnEnter={getAdditionalClasses}
|
|
getAdditionalClassesOnDroppable={getAdditionalClassesOnDroppable}
|
|
>
|
|
<button>Hello!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(1).simulate('dragover');
|
|
expect(component.find('.additional')).toHaveLength(2);
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(1).simulate('dragleave');
|
|
expect(setActiveDropTarget).toBeCalledWith(undefined);
|
|
});
|
|
|
|
describe('Keyboard navigation', () => {
|
|
test('User receives proper drop Targets highlighted when pressing arrow keys', () => {
|
|
const onDrop = jest.fn();
|
|
const setActiveDropTarget = jest.fn();
|
|
const setA11yMessage = jest.fn();
|
|
const items = [
|
|
{
|
|
draggable: true,
|
|
value: {
|
|
id: '1',
|
|
humanData: { label: 'Label1', position: 1 },
|
|
},
|
|
children: '1',
|
|
order: [2, 0, 0, 0],
|
|
},
|
|
{
|
|
draggable: true,
|
|
dragType: 'move' as 'copy' | 'move',
|
|
|
|
value: {
|
|
id: '2',
|
|
|
|
humanData: { label: 'label2', position: 1 },
|
|
},
|
|
onDrop,
|
|
dropTypes: ['move_compatible'] as DropType[],
|
|
order: [2, 0, 1, 0],
|
|
},
|
|
{
|
|
draggable: true,
|
|
dragType: 'move' as 'copy' | 'move',
|
|
value: {
|
|
id: '3',
|
|
humanData: {
|
|
label: 'label3',
|
|
position: 1,
|
|
groupLabel: 'Y',
|
|
canSwap: true,
|
|
canDuplicate: true,
|
|
},
|
|
},
|
|
onDrop,
|
|
dropTypes: [
|
|
'replace_compatible',
|
|
'duplicate_compatible',
|
|
'swap_compatible',
|
|
] as DropType[],
|
|
order: [2, 0, 2, 0],
|
|
},
|
|
{
|
|
draggable: true,
|
|
dragType: 'move' as 'copy' | 'move',
|
|
value: {
|
|
id: '4',
|
|
humanData: { label: 'label4', position: 2, groupLabel: 'Y' },
|
|
},
|
|
order: [2, 0, 2, 1],
|
|
},
|
|
];
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...{
|
|
...defaultContext,
|
|
dragging: { ...items[0].value, ghost: { children: <div />, style: {} } },
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
activeDropTarget: { ...items[1].value, onDrop, dropType: 'move_compatible' },
|
|
dropTargetsByOrder: {
|
|
'2,0,1,0': { ...items[1].value, onDrop, dropType: 'move_compatible' },
|
|
'2,0,2,0,0': { ...items[2].value, onDrop, dropType: 'replace_compatible' },
|
|
'2,0,1,0,1': { ...items[1].value, onDrop, dropType: 'duplicate_compatible' },
|
|
'2,0,1,0,2': { ...items[1].value, onDrop, dropType: 'swap_compatible' },
|
|
},
|
|
keyboardMode: true,
|
|
}}
|
|
>
|
|
{items.map((props) => (
|
|
<DragDrop {...props} key={props.value.id}>
|
|
<div />
|
|
</DragDrop>
|
|
))}
|
|
</ChildDragDropProvider>
|
|
);
|
|
const keyboardHandler = component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('focus');
|
|
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowRight' });
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[2].value,
|
|
onDrop,
|
|
dropType: items[2].dropTypes![0],
|
|
});
|
|
keyboardHandler.simulate('keydown', { key: 'Enter' });
|
|
expect(setA11yMessage).toBeCalledWith(
|
|
`You're dragging Label1 from at position 1 over label3 from Y group at position 1. Press space or enter to replace label3 with Label1. Hold alt or option to duplicate. Hold shift to swap.`
|
|
);
|
|
expect(setActiveDropTarget).toBeCalledWith(undefined);
|
|
expect(onDrop).toBeCalledWith(
|
|
{ humanData: { label: 'Label1', position: 1 }, id: '1' },
|
|
'move_compatible'
|
|
);
|
|
});
|
|
|
|
test('dragstart sets dragging in the context and calls it with proper params', async () => {
|
|
const setDragging = jest.fn();
|
|
|
|
const setA11yMessage = jest.fn();
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...defaultContext}
|
|
dragging={undefined}
|
|
setDragging={setDragging}
|
|
setA11yMessage={setA11yMessage}
|
|
keyboardMode={false}
|
|
>
|
|
<DragDrop value={value} draggable={true} order={[2, 0, 1, 0]}>
|
|
<button>Hi!</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
const keyboardHandler = component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('focus');
|
|
|
|
keyboardHandler.simulate('keydown', { key: 'Enter' });
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
expect(setDragging).toBeCalledWith({
|
|
...value,
|
|
ghost: {
|
|
children: <button>Hi!</button>,
|
|
style: {
|
|
height: 0,
|
|
width: 0,
|
|
},
|
|
},
|
|
});
|
|
expect(setA11yMessage).toBeCalledWith('Lifted hello');
|
|
});
|
|
|
|
test('ActiveDropTarget gets ghost image', () => {
|
|
const onDrop = jest.fn();
|
|
const setActiveDropTarget = jest.fn();
|
|
const setA11yMessage = jest.fn();
|
|
const items = [
|
|
{
|
|
draggable: true,
|
|
value: {
|
|
id: '1',
|
|
humanData: { label: 'Label1', position: 1 },
|
|
},
|
|
children: '1',
|
|
order: [2, 0, 0, 0],
|
|
},
|
|
{
|
|
draggable: true,
|
|
dragType: 'move' as 'copy' | 'move',
|
|
|
|
value: {
|
|
id: '2',
|
|
|
|
humanData: { label: 'label2', position: 1 },
|
|
},
|
|
onDrop,
|
|
dropTypes: ['move_compatible'] as DropType[],
|
|
order: [2, 0, 1, 0],
|
|
},
|
|
];
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...{
|
|
...defaultContext,
|
|
dragging: { ...items[0].value, ghost: { children: <div>Hello</div>, style: {} } },
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
activeDropTarget: { ...items[1].value, onDrop, dropType: 'move_compatible' },
|
|
dropTargetsByOrder: {
|
|
'2,0,1,0': { ...items[1].value, onDrop, dropType: 'move_compatible' },
|
|
},
|
|
keyboardMode: true,
|
|
}}
|
|
>
|
|
{items.map((props) => (
|
|
<DragDrop {...props} key={props.value.id}>
|
|
<div />
|
|
</DragDrop>
|
|
))}
|
|
</ChildDragDropProvider>
|
|
);
|
|
|
|
expect(component.find(DragDrop).at(1).find('.lnsDragDrop_ghost').text()).toEqual('Hello');
|
|
});
|
|
});
|
|
|
|
describe('multiple drop targets', () => {
|
|
let activeDropTarget: DragContextState['activeDropTarget'];
|
|
const onDrop = jest.fn();
|
|
let setActiveDropTarget = jest.fn();
|
|
const setA11yMessage = jest.fn();
|
|
let component: ReactWrapper;
|
|
beforeEach(() => {
|
|
activeDropTarget = undefined;
|
|
setActiveDropTarget = jest.fn((val) => {
|
|
activeDropTarget = value as DragContextState['activeDropTarget'];
|
|
});
|
|
component = mount(
|
|
<ChildDragDropProvider
|
|
setA11yMessage={jest.fn()}
|
|
dragging={{ id: '1', humanData: { label: 'Label1' } }}
|
|
setDragging={jest.fn()}
|
|
setActiveDropTarget={setActiveDropTarget}
|
|
activeDropTarget={activeDropTarget}
|
|
keyboardMode={false}
|
|
setKeyboardMode={(keyboardMode) => true}
|
|
dropTargetsByOrder={undefined}
|
|
registerDropTarget={jest.fn()}
|
|
>
|
|
<DragDrop
|
|
value={{ id: '3', humanData: { label: 'ignored' } }}
|
|
draggable={true}
|
|
order={[2, 0, 1, 0]}
|
|
>
|
|
<button>Drag this</button>
|
|
</DragDrop>
|
|
<DragDrop
|
|
order={[2, 0, 1, 0]}
|
|
value={value}
|
|
onDrop={onDrop}
|
|
dropTypes={['move_compatible', 'duplicate_compatible', 'swap_compatible']}
|
|
getCustomDropTarget={(dropType) => <div className="extraDrop">{dropType}</div>}
|
|
>
|
|
<button>Drop here</button>
|
|
</DragDrop>
|
|
</ChildDragDropProvider>
|
|
);
|
|
});
|
|
test('extra drop targets render correctly', () => {
|
|
expect(component.find('.extraDrop').hostNodes()).toHaveLength(2);
|
|
});
|
|
|
|
test('extra drop targets appear when dragging over and disappear when activeDropTarget changes', () => {
|
|
component.find('[data-test-subj="lnsDragDropContainer"]').first().simulate('dragenter');
|
|
|
|
// customDropTargets are visible
|
|
expect(component.find('[data-test-subj="lnsDragDropContainer"]').prop('className')).toEqual(
|
|
'lnsDragDrop__container lnsDragDrop__container-active'
|
|
);
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDropExtraDrops"]').first().prop('className')
|
|
).toEqual('lnsDragDrop__extraDrops lnsDragDrop__extraDrops-visible');
|
|
|
|
// set activeDropTarget as undefined
|
|
component.find('[data-test-subj="lnsDragDrop"]').at(1).simulate('dragleave');
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
component.update();
|
|
|
|
// customDropTargets are invisible
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDropExtraDrops"]').first().prop('className')
|
|
).toEqual('lnsDragDrop__extraDrops');
|
|
});
|
|
|
|
test('dragging over different drop types of the same value assigns correct activeDropTarget', () => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
|
|
component.find('SingleDropInner').at(0).simulate('dragover');
|
|
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...value,
|
|
dropType: 'move_compatible',
|
|
onDrop,
|
|
});
|
|
|
|
component.find('SingleDropInner').at(1).simulate('dragover');
|
|
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...value,
|
|
dropType: 'duplicate_compatible',
|
|
onDrop,
|
|
});
|
|
|
|
component.find('SingleDropInner').at(2).simulate('dragover');
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...value,
|
|
dropType: 'swap_compatible',
|
|
onDrop,
|
|
});
|
|
component.find('SingleDropInner').at(2).simulate('dragleave');
|
|
expect(setActiveDropTarget).toBeCalledWith(undefined);
|
|
});
|
|
|
|
test('drop on extra drop target passes correct dropType to onDrop', () => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
|
|
component.find('SingleDropInner').at(0).simulate('dragover');
|
|
component.find('SingleDropInner').at(0).simulate('drop');
|
|
expect(onDrop).toBeCalledWith({ humanData: { label: 'Label1' }, id: '1' }, 'move_compatible');
|
|
|
|
component.find('SingleDropInner').at(1).simulate('dragover');
|
|
component.find('SingleDropInner').at(1).simulate('drop');
|
|
expect(onDrop).toBeCalledWith(
|
|
{ humanData: { label: 'Label1' }, id: '1' },
|
|
'duplicate_compatible'
|
|
);
|
|
|
|
component.find('SingleDropInner').at(2).simulate('dragover');
|
|
component.find('SingleDropInner').at(2).simulate('drop');
|
|
expect(onDrop).toBeCalledWith({ humanData: { label: 'Label1' }, id: '1' }, 'swap_compatible');
|
|
});
|
|
|
|
test('pressing Alt or Shift when dragging over the main drop target sets extra drop target as active', () => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
|
|
// needed to setup activeDropType
|
|
component
|
|
.find('SingleDropInner')
|
|
.at(0)
|
|
.simulate('dragover', { altKey: true })
|
|
.simulate('dragover', { altKey: true });
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...value,
|
|
dropType: 'duplicate_compatible',
|
|
onDrop,
|
|
});
|
|
|
|
component
|
|
.find('SingleDropInner')
|
|
.at(0)
|
|
.simulate('dragover', { shiftKey: true })
|
|
.simulate('dragover', { shiftKey: true });
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...value,
|
|
dropType: 'swap_compatible',
|
|
onDrop,
|
|
});
|
|
});
|
|
|
|
test('pressing Alt or Shift when dragging over the extra drop target does nothing', () => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
|
|
const extraDrop = component.find('SingleDropInner').at(1);
|
|
extraDrop.simulate('dragover', { altKey: true });
|
|
extraDrop.simulate('dragover', { shiftKey: true });
|
|
extraDrop.simulate('dragover');
|
|
expect(
|
|
setActiveDropTarget.mock.calls.every((call) => call[0].dropType === 'duplicate_compatible')
|
|
);
|
|
});
|
|
describe('keyboard navigation', () => {
|
|
const items = [
|
|
{
|
|
draggable: true,
|
|
value: {
|
|
id: '1',
|
|
humanData: { label: 'Label1', position: 1 },
|
|
},
|
|
children: '1',
|
|
order: [2, 0, 0, 0],
|
|
},
|
|
{
|
|
draggable: true,
|
|
dragType: 'move' as const,
|
|
|
|
value: {
|
|
id: '2',
|
|
|
|
humanData: { label: 'label2', position: 1 },
|
|
},
|
|
onDrop,
|
|
dropTypes: ['move_compatible', 'duplicate_compatible', 'swap_compatible'] as DropType[],
|
|
order: [2, 0, 1, 0],
|
|
},
|
|
{
|
|
draggable: true,
|
|
dragType: 'move' as const,
|
|
value: {
|
|
id: '3',
|
|
humanData: { label: 'label3', position: 1, groupLabel: 'Y' },
|
|
},
|
|
onDrop,
|
|
dropTypes: ['replace_compatible'] as DropType[],
|
|
order: [2, 0, 2, 0],
|
|
},
|
|
];
|
|
const assignedDropTargetsByOrder: DragContextState['dropTargetsByOrder'] = {
|
|
'2,0,1,0,0': {
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'move_compatible',
|
|
},
|
|
'2,0,1,0,1': {
|
|
dropType: 'duplicate_compatible',
|
|
humanData: {
|
|
label: 'label2',
|
|
position: 1,
|
|
},
|
|
id: '2',
|
|
onDrop,
|
|
},
|
|
'2,0,1,0,2': {
|
|
dropType: 'swap_compatible',
|
|
humanData: {
|
|
label: 'label2',
|
|
position: 1,
|
|
},
|
|
id: '2',
|
|
onDrop,
|
|
},
|
|
'2,0,2,0,0': {
|
|
dropType: 'replace_compatible',
|
|
humanData: {
|
|
groupLabel: 'Y',
|
|
label: 'label3',
|
|
position: 1,
|
|
},
|
|
id: '3',
|
|
onDrop,
|
|
},
|
|
};
|
|
test('when pressing enter key, context receives the proper dropTargetsByOrder', () => {
|
|
let dropTargetsByOrder: DragContextState['dropTargetsByOrder'] = {};
|
|
const setKeyboardMode = jest.fn();
|
|
component = mount(
|
|
<ChildDragDropProvider
|
|
{...{
|
|
...defaultContext,
|
|
dragging: { ...items[0].value, ghost: { children: <div />, style: {} } },
|
|
setDragging: jest.fn(),
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
activeDropTarget,
|
|
dropTargetsByOrder,
|
|
keyboardMode: true,
|
|
setKeyboardMode,
|
|
registerDropTarget: jest.fn((order, dropTarget) => {
|
|
dropTargetsByOrder = {
|
|
...dropTargetsByOrder,
|
|
[order.join(',')]: dropTarget,
|
|
};
|
|
}),
|
|
}}
|
|
>
|
|
{items.map((props) => (
|
|
<DragDrop {...props} key={props.value.id}>
|
|
<div />
|
|
</DragDrop>
|
|
))}
|
|
</ChildDragDropProvider>
|
|
);
|
|
component.find('[data-test-subj="lnsDragDrop-keyboardHandler"]').first().simulate('focus');
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
component.update();
|
|
expect(dropTargetsByOrder).toEqual(assignedDropTargetsByOrder);
|
|
});
|
|
test('when pressing ArrowRight key with modifier key pressed in, the extra drop target is selected', () => {
|
|
component = mount(
|
|
<ChildDragDropProvider
|
|
{...{
|
|
...defaultContext,
|
|
dragging: { ...items[0].value, ghost: { children: <div />, style: {} } },
|
|
setDragging: jest.fn(),
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
activeDropTarget: undefined,
|
|
dropTargetsByOrder: assignedDropTargetsByOrder,
|
|
keyboardMode: true,
|
|
setKeyboardMode: jest.fn(),
|
|
registerDropTarget: jest.fn(),
|
|
}}
|
|
>
|
|
{items.map((props) => (
|
|
<DragDrop {...props} key={props.value.id}>
|
|
<div />
|
|
</DragDrop>
|
|
))}
|
|
</ChildDragDropProvider>
|
|
);
|
|
act(() => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('keydown', { key: 'ArrowRight', altKey: true });
|
|
});
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'duplicate_compatible',
|
|
});
|
|
act(() => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('keydown', { key: 'ArrowRight', shiftKey: true });
|
|
});
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'swap_compatible',
|
|
});
|
|
});
|
|
test('when having a main target selected and pressing alt, the first extra drop target is selected', () => {
|
|
component = mount(
|
|
<ChildDragDropProvider
|
|
{...{
|
|
...defaultContext,
|
|
dragging: { ...items[0].value, ghost: { children: <div />, style: {} } },
|
|
setDragging: jest.fn(),
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
activeDropTarget: assignedDropTargetsByOrder['2,0,1,0,0'],
|
|
dropTargetsByOrder: assignedDropTargetsByOrder,
|
|
keyboardMode: true,
|
|
setKeyboardMode: jest.fn(),
|
|
registerDropTarget: jest.fn(),
|
|
}}
|
|
>
|
|
{items.map((props) => (
|
|
<DragDrop {...props} key={props.value.id}>
|
|
<div />
|
|
</DragDrop>
|
|
))}
|
|
</ChildDragDropProvider>
|
|
);
|
|
act(() => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('keydown', { key: 'Alt' });
|
|
});
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'duplicate_compatible',
|
|
});
|
|
act(() => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('keyup', { key: 'Alt' });
|
|
});
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'move_compatible',
|
|
});
|
|
});
|
|
test('when having a main target selected and pressing shift, the second extra drop target is selected', () => {
|
|
component = mount(
|
|
<ChildDragDropProvider
|
|
{...{
|
|
...defaultContext,
|
|
dragging: { ...items[0].value, ghost: { children: <div />, style: {} } },
|
|
setDragging: jest.fn(),
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
activeDropTarget: assignedDropTargetsByOrder['2,0,1,0,0'],
|
|
dropTargetsByOrder: assignedDropTargetsByOrder,
|
|
keyboardMode: true,
|
|
setKeyboardMode: jest.fn(),
|
|
registerDropTarget: jest.fn(),
|
|
}}
|
|
>
|
|
{items.map((props) => (
|
|
<DragDrop {...props} key={props.value.id}>
|
|
<div />
|
|
</DragDrop>
|
|
))}
|
|
</ChildDragDropProvider>
|
|
);
|
|
act(() => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('keydown', { key: 'Shift' });
|
|
});
|
|
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'swap_compatible',
|
|
});
|
|
act(() => {
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('keyup', { key: 'Shift' });
|
|
});
|
|
expect(setActiveDropTarget).toBeCalledWith({
|
|
...items[1].value,
|
|
onDrop,
|
|
dropType: 'move_compatible',
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Reordering', () => {
|
|
const onDrop = jest.fn();
|
|
const items = [
|
|
{
|
|
id: '1',
|
|
humanData: { label: 'Label1', position: 1, groupLabel: 'X' },
|
|
onDrop,
|
|
draggable: true,
|
|
},
|
|
{
|
|
id: '2',
|
|
humanData: { label: 'label2', position: 2, groupLabel: 'X' },
|
|
onDrop,
|
|
},
|
|
{
|
|
id: '3',
|
|
humanData: { label: 'label3', position: 3, groupLabel: 'X' },
|
|
onDrop,
|
|
},
|
|
];
|
|
const mountComponent = (
|
|
dragContext: Partial<DragContextState> | undefined,
|
|
onDropHandler?: () => void
|
|
) => {
|
|
let dragging = dragContext?.dragging;
|
|
let keyboardMode = !!dragContext?.keyboardMode;
|
|
let activeDropTarget = dragContext?.activeDropTarget;
|
|
|
|
const setA11yMessage = jest.fn();
|
|
const registerDropTarget = jest.fn();
|
|
const baseContext = {
|
|
dragging,
|
|
setDragging: (val?: DraggingIdentifier) => {
|
|
dragging = val;
|
|
},
|
|
keyboardMode,
|
|
setKeyboardMode: jest.fn((mode) => {
|
|
keyboardMode = mode;
|
|
}),
|
|
setActiveDropTarget: (target?: DragDropIdentifier) => {
|
|
activeDropTarget = target as DropIdentifier;
|
|
},
|
|
activeDropTarget,
|
|
setA11yMessage,
|
|
registerDropTarget,
|
|
dropTargetsByOrder: undefined,
|
|
};
|
|
|
|
const dragDropSharedProps = {
|
|
draggable: true,
|
|
dragType: 'move' as 'copy' | 'move',
|
|
reorderableGroup: items.map(({ id }) => ({ id })),
|
|
onDrop: onDropHandler || onDrop,
|
|
};
|
|
|
|
return mount(
|
|
<ChildDragDropProvider {...baseContext} {...dragContext}>
|
|
<ReorderProvider id="groupId">
|
|
<DragDrop
|
|
{...dragDropSharedProps}
|
|
value={items[0]}
|
|
dropTypes={undefined}
|
|
order={[2, 0, 0]}
|
|
>
|
|
<span>1</span>
|
|
</DragDrop>
|
|
<DragDrop
|
|
{...dragDropSharedProps}
|
|
value={items[1]}
|
|
order={[2, 0, 1]}
|
|
dropTypes={['reorder']}
|
|
>
|
|
<span>2</span>
|
|
</DragDrop>
|
|
<DragDrop
|
|
{...dragDropSharedProps}
|
|
value={items[2]}
|
|
order={[2, 0, 2]}
|
|
dropTypes={['reorder']}
|
|
>
|
|
<span>3</span>
|
|
</DragDrop>
|
|
</ReorderProvider>
|
|
</ChildDragDropProvider>
|
|
);
|
|
};
|
|
test(`Inactive group renders properly`, () => {
|
|
const component = mountComponent(undefined);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
expect(component.find('[data-test-subj="lnsDragDrop"]')).toHaveLength(5);
|
|
});
|
|
|
|
test(`Reorderable group with lifted element renders properly`, () => {
|
|
const setA11yMessage = jest.fn();
|
|
const setDragging = jest.fn();
|
|
const component = mountComponent({
|
|
dragging: { ...items[0] },
|
|
setDragging,
|
|
setA11yMessage,
|
|
});
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
expect(setDragging).toBeCalledWith({ ...items[0] });
|
|
expect(setA11yMessage).toBeCalledWith('Lifted Label1');
|
|
});
|
|
|
|
test(`Reordered elements get extra styles to show the reorder effect when dragging`, () => {
|
|
const component = mountComponent({ dragging: { ...items[0] } });
|
|
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop"]')
|
|
.first()
|
|
.simulate('dragstart', { dataTransfer });
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-reorderableDropLayer"]')
|
|
.at(1)
|
|
.simulate('dragover');
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-reorderableDrag"]').at(0).prop('style')
|
|
).toEqual(undefined);
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-translatableDrop"]').at(0).prop('style')
|
|
).toEqual({
|
|
transform: 'translateY(-8px)',
|
|
});
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-translatableDrop"]').at(1).prop('style')
|
|
).toEqual({
|
|
transform: 'translateY(-8px)',
|
|
});
|
|
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-reorderableDropLayer"]')
|
|
.at(1)
|
|
.simulate('dragleave');
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-reorderableDrag"]').at(0).prop('style')
|
|
).toEqual(undefined);
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-translatableDrop"]').at(1).prop('style')
|
|
).toEqual(undefined);
|
|
});
|
|
|
|
test(`Dropping an item runs onDrop function`, () => {
|
|
const preventDefault = jest.fn();
|
|
const stopPropagation = jest.fn();
|
|
|
|
const setA11yMessage = jest.fn();
|
|
const setDragging = jest.fn();
|
|
|
|
const component = mountComponent({
|
|
dragging: { ...items[0] },
|
|
setDragging,
|
|
setA11yMessage,
|
|
});
|
|
|
|
const dragDrop = component.find('[data-test-subj="lnsDragDrop-reorderableDropLayer"]').at(1);
|
|
dragDrop.simulate('dragOver');
|
|
dragDrop.simulate('drop', { preventDefault, stopPropagation });
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
expect(setA11yMessage).toBeCalledWith(
|
|
'Reordered Label1 in X group from position 1 to position 3'
|
|
);
|
|
expect(preventDefault).toBeCalled();
|
|
expect(stopPropagation).toBeCalled();
|
|
expect(onDrop).toBeCalledWith({ ...items[0] }, 'reorder');
|
|
});
|
|
|
|
test(`Keyboard Navigation: User cannot move an element outside of the group`, () => {
|
|
const setA11yMessage = jest.fn();
|
|
const setActiveDropTarget = jest.fn();
|
|
const component = mountComponent({
|
|
dragging: { ...items[0] },
|
|
keyboardMode: true,
|
|
activeDropTarget: undefined,
|
|
dropTargetsByOrder: {
|
|
'2,0,0': undefined,
|
|
'2,0,1': { ...items[1], onDrop, dropType: 'reorder' },
|
|
'2,0,2': { ...items[2], onDrop, dropType: 'reorder' },
|
|
},
|
|
setActiveDropTarget,
|
|
setA11yMessage,
|
|
});
|
|
const keyboardHandler = component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first();
|
|
|
|
keyboardHandler.simulate('keydown', { key: 'Space' });
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowUp' });
|
|
expect(setActiveDropTarget).not.toHaveBeenCalled();
|
|
|
|
keyboardHandler.simulate('keydown', { key: 'Space' });
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
|
|
|
|
expect(setActiveDropTarget).toBeCalledWith({ ...items[1], dropType: 'reorder' });
|
|
expect(setA11yMessage).toBeCalledWith(
|
|
'Reorder Label1 in X group from position 1 to position 2. Press space or enter to reorder'
|
|
);
|
|
});
|
|
|
|
test(`Keyboard navigation: user can drop element to an activeDropTarget`, () => {
|
|
const component = mountComponent({
|
|
dragging: { ...items[0] },
|
|
activeDropTarget: { ...items[2], dropType: 'reorder', onDrop },
|
|
dropTargetsByOrder: {
|
|
'2,0,0': { ...items[0], onDrop, dropType: 'reorder' },
|
|
'2,0,1': { ...items[1], onDrop, dropType: 'reorder' },
|
|
'2,0,2': { ...items[2], onDrop, dropType: 'reorder' },
|
|
},
|
|
keyboardMode: true,
|
|
});
|
|
const keyboardHandler = component
|
|
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
|
|
.first()
|
|
.simulate('focus');
|
|
|
|
act(() => {
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
|
|
keyboardHandler.simulate('keydown', { key: 'Enter' });
|
|
});
|
|
expect(onDrop).toBeCalledWith(items[0], 'reorder');
|
|
});
|
|
|
|
test(`Keyboard Navigation: Doesn't call onDrop when movement is cancelled`, () => {
|
|
const setA11yMessage = jest.fn();
|
|
const onDropHandler = jest.fn();
|
|
const component = mountComponent(
|
|
{ dragging: { ...items[0] }, setA11yMessage },
|
|
onDropHandler
|
|
);
|
|
const keyboardHandler = component.find('[data-test-subj="lnsDragDrop-keyboardHandler"]');
|
|
keyboardHandler.simulate('keydown', { key: 'Space' });
|
|
keyboardHandler.simulate('keydown', { key: 'Escape' });
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
expect(onDropHandler).not.toHaveBeenCalled();
|
|
expect(setA11yMessage).toBeCalledWith(
|
|
'Movement cancelled. Label1 returned to X group at position 1'
|
|
);
|
|
keyboardHandler.simulate('keydown', { key: 'Space' });
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
|
|
keyboardHandler.simulate('blur');
|
|
|
|
expect(onDropHandler).not.toHaveBeenCalled();
|
|
expect(setA11yMessage).toBeCalledWith(
|
|
'Movement cancelled. Label1 returned to X group at position 1'
|
|
);
|
|
});
|
|
|
|
test(`Keyboard Navigation: Reordered elements get extra styles to show the reorder effect`, () => {
|
|
const setA11yMessage = jest.fn();
|
|
const component = mountComponent({
|
|
dragging: { ...items[0] },
|
|
keyboardMode: true,
|
|
activeDropTarget: undefined,
|
|
dropTargetsByOrder: {
|
|
'2,0,0': undefined,
|
|
'2,0,1': { ...items[1], onDrop, dropType: 'reorder' },
|
|
'2,0,2': { ...items[2], onDrop, dropType: 'reorder' },
|
|
},
|
|
setA11yMessage,
|
|
});
|
|
|
|
const keyboardHandler = component.find('[data-test-subj="lnsDragDrop-keyboardHandler"]');
|
|
keyboardHandler.simulate('keydown', { key: 'Space' });
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
|
|
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-reorderableDrag"]').at(0).prop('style')
|
|
).toEqual({
|
|
transform: 'translateY(+8px)',
|
|
});
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-translatableDrop"]').at(0).prop('style')
|
|
).toEqual({
|
|
transform: 'translateY(-40px)',
|
|
});
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-translatableDrop"]').at(1).prop('style')
|
|
).toEqual(undefined);
|
|
expect(setA11yMessage).toBeCalledWith(
|
|
'Reorder Label1 in X group from position 1 to position 2. Press space or enter to reorder'
|
|
);
|
|
|
|
component
|
|
.find('[data-test-subj="lnsDragDrop-reorderableDropLayer"]')
|
|
.at(1)
|
|
.simulate('dragleave');
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-reorderableDrag"]').at(0).prop('style')
|
|
).toEqual(undefined);
|
|
expect(
|
|
component.find('[data-test-subj="lnsDragDrop-translatableDrop"]').at(1).prop('style')
|
|
).toEqual(undefined);
|
|
});
|
|
|
|
test(`Keyboard Navigation: User cannot drop element to itself`, () => {
|
|
const setA11yMessage = jest.fn();
|
|
const setActiveDropTarget = jest.fn();
|
|
const component = mount(
|
|
<ChildDragDropProvider
|
|
{...defaultContext}
|
|
keyboardMode={true}
|
|
activeDropTarget={{
|
|
...items[1],
|
|
onDrop,
|
|
dropType: 'reorder',
|
|
}}
|
|
dropTargetsByOrder={{
|
|
'2,0,1,0': undefined,
|
|
'2,0,1,1': { ...items[1], onDrop, dropType: 'reorder' },
|
|
}}
|
|
dragging={{ ...items[0] }}
|
|
setActiveDropTarget={setActiveDropTarget}
|
|
setA11yMessage={setA11yMessage}
|
|
>
|
|
<ReorderProvider id="groupId">
|
|
<DragDrop
|
|
draggable
|
|
dragType="move"
|
|
reorderableGroup={[items[0], items[1]]}
|
|
value={items[0]}
|
|
order={[2, 0, 1, 0]}
|
|
>
|
|
<span>1</span>
|
|
</DragDrop>
|
|
<DragDrop
|
|
draggable
|
|
dragType="move"
|
|
dropTypes={['reorder']}
|
|
reorderableGroup={[items[0], items[1]]}
|
|
value={items[1]}
|
|
order={[2, 0, 1, 1]}
|
|
>
|
|
<span>2</span>
|
|
</DragDrop>
|
|
</ReorderProvider>
|
|
</ChildDragDropProvider>
|
|
);
|
|
const keyboardHandler = component.find('[data-test-subj="lnsDragDrop-keyboardHandler"]');
|
|
|
|
keyboardHandler.simulate('keydown', { key: 'Space' });
|
|
keyboardHandler.simulate('keydown', { key: 'ArrowUp' });
|
|
expect(setActiveDropTarget).toBeCalledWith(undefined);
|
|
expect(setA11yMessage).toBeCalledWith('Label1 returned to its initial position 1');
|
|
});
|
|
});
|
|
});
|