mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
test(drag-drop): add missing unit tests (#12219)
This commit is contained in:
committed by
Joey Perrott
parent
9d53f670f2
commit
19326f76fc
@@ -0,0 +1,69 @@
|
||||
import {moveItemInArray, transferArrayItem} from './drag-utils';
|
||||
|
||||
describe('dragging utilities', () => {
|
||||
describe('moveItemInArray', () => {
|
||||
let array: number[];
|
||||
|
||||
beforeEach(() => array = [0, 1, 2, 3]);
|
||||
|
||||
it('should be able to move an item inside an array', () => {
|
||||
moveItemInArray(array, 1, 3);
|
||||
expect(array).toEqual([0, 2, 3, 1]);
|
||||
});
|
||||
|
||||
it('should not do anything if the index is the same', () => {
|
||||
moveItemInArray(array, 2, 2);
|
||||
expect(array).toEqual([0, 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should handle an index greater than the length', () => {
|
||||
moveItemInArray(array, 0, 7);
|
||||
expect(array).toEqual([1, 2, 3, 0]);
|
||||
});
|
||||
|
||||
it('should handle an index less than zero', () => {
|
||||
moveItemInArray(array, 3, -1);
|
||||
expect(array).toEqual([3, 0, 1, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferArrayItem', () => {
|
||||
it('should be able to move an item from one array to another', () => {
|
||||
const a = [0, 1, 2];
|
||||
const b = [3, 4, 5];
|
||||
|
||||
transferArrayItem(a, b, 1, 2);
|
||||
expect(a).toEqual([0, 2]);
|
||||
expect(b).toEqual([3, 4, 1, 5]);
|
||||
});
|
||||
|
||||
it('should handle an index greater than the target array length', () => {
|
||||
const a = [0, 1, 2];
|
||||
const b = [3, 4, 5];
|
||||
|
||||
transferArrayItem(a, b, 0, 7);
|
||||
|
||||
expect(a).toEqual([1, 2]);
|
||||
expect(b).toEqual([3, 4, 5, 0]);
|
||||
});
|
||||
|
||||
it('should handle an index less than zero', () => {
|
||||
const a = [0, 1, 2];
|
||||
const b = [3, 4, 5];
|
||||
|
||||
transferArrayItem(a, b, 2, -1);
|
||||
expect(a).toEqual([0, 1]);
|
||||
expect(b).toEqual([2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
it('should not do anything if the source array is empty', () => {
|
||||
const a = [];
|
||||
const b = [3, 4, 5];
|
||||
|
||||
transferArrayItem(a, b, 0, 0);
|
||||
expect(a).toEqual([]);
|
||||
expect(b).toEqual([3, 4, 5]);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -13,18 +13,21 @@
|
||||
* @param toIndex Index to which the item should be moved.
|
||||
*/
|
||||
export function moveItemInArray<T = any>(array: T[], fromIndex: number, toIndex: number): void {
|
||||
if (fromIndex === toIndex) {
|
||||
const from = clamp(fromIndex, array.length - 1);
|
||||
const to = clamp(toIndex, array.length - 1);
|
||||
|
||||
if (from === to) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = array[fromIndex];
|
||||
const delta = toIndex < fromIndex ? -1 : 1;
|
||||
const target = array[from];
|
||||
const delta = to < from ? -1 : 1;
|
||||
|
||||
for (let i = fromIndex; i !== toIndex; i += delta) {
|
||||
for (let i = from; i !== to; i += delta) {
|
||||
array[i] = array[i + delta];
|
||||
}
|
||||
|
||||
array[toIndex] = target;
|
||||
array[to] = target;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,5 +42,16 @@ export function transferArrayItem<T = any>(currentArray: T[],
|
||||
targetArray: T[],
|
||||
currentIndex: number,
|
||||
targetIndex: number): void {
|
||||
targetArray.splice(targetIndex, 0, currentArray.splice(currentIndex, 1)[0]);
|
||||
|
||||
const from = clamp(currentIndex, currentArray.length - 1);
|
||||
const to = clamp(targetIndex, targetArray.length);
|
||||
|
||||
if (currentArray.length) {
|
||||
targetArray.splice(to, 0, currentArray.splice(from, 1)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Clamps a number between zero and a maximum. */
|
||||
function clamp(value: number, max: number): number {
|
||||
return Math.max(0, Math.min(max, value));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {dispatchMouseEvent, dispatchTouchEvent} from '@angular/cdk/testing';
|
||||
import {Directionality} from '@angular/cdk/bidi';
|
||||
import {CdkDrag} from './drag';
|
||||
import {CdkDragDrop} from './drag-events';
|
||||
import {moveItemInArray, transferArrayItem} from './drag-utils';
|
||||
import {moveItemInArray} from './drag-utils';
|
||||
import {CdkDrop} from './drop';
|
||||
import {CdkDragHandle} from './drag-handle';
|
||||
|
||||
@@ -460,7 +460,9 @@ describe('CdkDrag', () => {
|
||||
it('should move the placeholder as an item is being sorted down', fakeAsync(() => {
|
||||
const fixture = createComponent(DraggableInDropZone);
|
||||
fixture.detectChanges();
|
||||
assertDownwardSorting(fixture);
|
||||
assertDownwardSorting(fixture, fixture.componentInstance.dragItems.map(item => {
|
||||
return item.element.nativeElement;
|
||||
}));
|
||||
}));
|
||||
|
||||
it('should move the placeholder as an item is being sorted down on a scrolled page',
|
||||
@@ -470,14 +472,18 @@ describe('CdkDrag', () => {
|
||||
const cleanup = makePageScrollable();
|
||||
|
||||
scrollTo(0, 500);
|
||||
assertDownwardSorting(fixture);
|
||||
assertDownwardSorting(fixture, fixture.componentInstance.dragItems.map(item => {
|
||||
return item.element.nativeElement;
|
||||
}));
|
||||
cleanup();
|
||||
}));
|
||||
|
||||
it('should move the placeholder as an item is being sorted up', fakeAsync(() => {
|
||||
const fixture = createComponent(DraggableInDropZone);
|
||||
fixture.detectChanges();
|
||||
assertUpwardSorting(fixture);
|
||||
assertUpwardSorting(fixture, fixture.componentInstance.dragItems.map(item => {
|
||||
return item.element.nativeElement;
|
||||
}));
|
||||
}));
|
||||
|
||||
it('should move the placeholder as an item is being sorted up on a scrolled page',
|
||||
@@ -487,7 +493,9 @@ describe('CdkDrag', () => {
|
||||
const cleanup = makePageScrollable();
|
||||
|
||||
scrollTo(0, 500);
|
||||
assertUpwardSorting(fixture);
|
||||
assertUpwardSorting(fixture, fixture.componentInstance.dragItems.map(item => {
|
||||
return item.element.nativeElement;
|
||||
}));
|
||||
cleanup();
|
||||
}));
|
||||
|
||||
@@ -617,9 +625,127 @@ describe('CdkDrag', () => {
|
||||
const fixture = createComponent(ConnectedDropZones);
|
||||
fixture.detectChanges();
|
||||
|
||||
// TODO
|
||||
// console.log(fixture.componentInstance.groupedDragItems.map(d => d.length));
|
||||
const groups = fixture.componentInstance.groupedDragItems;
|
||||
const item = groups[0][1];
|
||||
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
|
||||
|
||||
dragElementViaMouse(fixture, item.element.nativeElement,
|
||||
targetRect.left + 1, targetRect.top + 1);
|
||||
flush();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.droppedSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
const event = fixture.componentInstance.droppedSpy.calls.mostRecent().args[0];
|
||||
|
||||
expect(event).toEqual({
|
||||
previousIndex: 1,
|
||||
currentIndex: 3,
|
||||
item,
|
||||
container: fixture.componentInstance.dropInstances.toArray()[1],
|
||||
previousContainer: fixture.componentInstance.dropInstances.first
|
||||
});
|
||||
}));
|
||||
|
||||
it('should be able to move the element over a new container and return it', fakeAsync(() => {
|
||||
const fixture = createComponent(ConnectedDropZones);
|
||||
fixture.detectChanges();
|
||||
|
||||
const groups = fixture.componentInstance.groupedDragItems;
|
||||
const dropZones = fixture.componentInstance.dropInstances.map(d => d.element.nativeElement);
|
||||
const item = groups[0][1];
|
||||
const initialRect = item.element.nativeElement.getBoundingClientRect();
|
||||
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
|
||||
|
||||
expect(dropZones[0].contains(item.element.nativeElement)).toBe(true);
|
||||
dispatchMouseEvent(item.element.nativeElement, 'mousedown');
|
||||
fixture.detectChanges();
|
||||
|
||||
const placeholder = dropZones[0].querySelector('.cdk-drag-placeholder')!;
|
||||
|
||||
expect(placeholder).toBeTruthy();
|
||||
|
||||
dispatchMouseEvent(document, 'mousemove', targetRect.left + 1, targetRect.top + 1);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(dropZones[1].contains(placeholder))
|
||||
.toBe(true, 'Expected placeholder to be inside second container.');
|
||||
|
||||
dispatchMouseEvent(document, 'mousemove', initialRect.left + 1, initialRect.top + 1);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(dropZones[0].contains(placeholder))
|
||||
.toBe(true, 'Expected placeholder to be inside first container.');
|
||||
|
||||
dispatchMouseEvent(document, 'mouseup');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.droppedSpy).not.toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should transfer the DOM element from one drop zone to another', fakeAsync(() => {
|
||||
const fixture = createComponent(ConnectedDropZones);
|
||||
fixture.detectChanges();
|
||||
|
||||
const groups = fixture.componentInstance.groupedDragItems;
|
||||
const element = groups[0][1].element.nativeElement;
|
||||
const dropZones = fixture.componentInstance.dropInstances.map(d => d.element.nativeElement);
|
||||
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
|
||||
|
||||
expect(dropZones[0].contains(element)).toBe(true);
|
||||
|
||||
dragElementViaMouse(fixture, element, targetRect.left + 1, targetRect.top + 1);
|
||||
flush();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(dropZones[1].contains(element)).toBe(true);
|
||||
}));
|
||||
|
||||
it('should not be able to transfer an item into a container that is not in `connectedTo`',
|
||||
fakeAsync(() => {
|
||||
const fixture = createComponent(ConnectedDropZones);
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.dropInstances.forEach(d => d.connectedTo = []);
|
||||
fixture.detectChanges();
|
||||
|
||||
const groups = fixture.componentInstance.groupedDragItems;
|
||||
const element = groups[0][1].element.nativeElement;
|
||||
const dropZones = fixture.componentInstance.dropInstances.map(d => d.element.nativeElement);
|
||||
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
|
||||
|
||||
expect(dropZones[0].contains(element)).toBe(true);
|
||||
|
||||
dragElementViaMouse(fixture, element, targetRect.left + 1, targetRect.top + 1);
|
||||
flush();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(dropZones[0].contains(element)).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should be able to start dragging after an item has been transferred', fakeAsync(() => {
|
||||
const fixture = createComponent(ConnectedDropZones);
|
||||
fixture.detectChanges();
|
||||
|
||||
const groups = fixture.componentInstance.groupedDragItems;
|
||||
const element = groups[0][1].element.nativeElement;
|
||||
const dropZones = fixture.componentInstance.dropInstances.map(d => d.element.nativeElement);
|
||||
const targetRect = dropZones[1].getBoundingClientRect();
|
||||
|
||||
expect(dropZones[0].contains(element)).toBe(true);
|
||||
|
||||
// Drag the element into the drop zone and move it to the top.
|
||||
[1, -1].forEach(offset => {
|
||||
dragElementViaMouse(fixture, element, targetRect.left + offset, targetRect.top + offset);
|
||||
flush();
|
||||
fixture.detectChanges();
|
||||
expect(dropZones[1].contains(element)).toBe(true);
|
||||
});
|
||||
|
||||
assertDownwardSorting(fixture, Array.from(dropZones[1].querySelectorAll('.cdk-drag')));
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -821,20 +947,9 @@ export class ConnectedDropZones implements AfterViewInit {
|
||||
@ViewChildren(CdkDrop) dropInstances: QueryList<CdkDrop>;
|
||||
|
||||
groupedDragItems: CdkDrag[][] = [];
|
||||
|
||||
todo = ['Zero', 'One', 'Two', 'Three'];
|
||||
done = ['Four', 'Five', 'Six'];
|
||||
|
||||
droppedSpy = jasmine.createSpy('dropped spy').and.callFake((event: CdkDragDrop<string[]>) => {
|
||||
if (event.previousContainer === event.container) {
|
||||
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
|
||||
} else {
|
||||
transferArrayItem(event.previousContainer.data,
|
||||
event.container.data,
|
||||
event.previousIndex,
|
||||
event.currentIndex);
|
||||
}
|
||||
});
|
||||
droppedSpy = jasmine.createSpy('dropped spy');
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.dropInstances.forEach((dropZone, index) => {
|
||||
@@ -913,10 +1028,10 @@ function makePageScrollable() {
|
||||
/**
|
||||
* Asserts that sorting an element down works correctly.
|
||||
* @param fixture Fixture against which to run the assertions.
|
||||
* @param items Array of items against which to test sorting.
|
||||
*/
|
||||
function assertDownwardSorting(fixture: ComponentFixture<DraggableInDropZone>) {
|
||||
const items = fixture.componentInstance.dragItems.toArray();
|
||||
const draggedItem = items[0].element.nativeElement;
|
||||
function assertDownwardSorting(fixture: ComponentFixture<any>, items: Element[]) {
|
||||
const draggedItem = items[0];
|
||||
const {top, left} = draggedItem.getBoundingClientRect();
|
||||
|
||||
dispatchMouseEvent(draggedItem, 'mousedown', left, top);
|
||||
@@ -926,7 +1041,7 @@ function assertDownwardSorting(fixture: ComponentFixture<DraggableInDropZone>) {
|
||||
|
||||
// Drag over each item one-by-one going downwards.
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const elementRect = items[i].element.nativeElement.getBoundingClientRect();
|
||||
const elementRect = items[i].getBoundingClientRect();
|
||||
|
||||
// Add a few pixels to the top offset so we get some overlap.
|
||||
dispatchMouseEvent(document, 'mousemove', elementRect.left, elementRect.top + 5);
|
||||
@@ -942,10 +1057,10 @@ function assertDownwardSorting(fixture: ComponentFixture<DraggableInDropZone>) {
|
||||
/**
|
||||
* Asserts that sorting an element up works correctly.
|
||||
* @param fixture Fixture against which to run the assertions.
|
||||
* @param items Array of items against which to test sorting.
|
||||
*/
|
||||
function assertUpwardSorting(fixture: ComponentFixture<DraggableInDropZone>) {
|
||||
const items = fixture.componentInstance.dragItems.toArray();
|
||||
const draggedItem = items[items.length - 1].element.nativeElement;
|
||||
function assertUpwardSorting(fixture: ComponentFixture<any>, items: Element[]) {
|
||||
const draggedItem = items[items.length - 1];
|
||||
const {top, left} = draggedItem.getBoundingClientRect();
|
||||
|
||||
dispatchMouseEvent(draggedItem, 'mousedown', left, top);
|
||||
@@ -955,7 +1070,7 @@ function assertUpwardSorting(fixture: ComponentFixture<DraggableInDropZone>) {
|
||||
|
||||
// Drag over each item one-by-one going upwards.
|
||||
for (let i = items.length - 1; i > -1; i--) {
|
||||
const elementRect = items[i].element.nativeElement.getBoundingClientRect();
|
||||
const elementRect = items[i].getBoundingClientRect();
|
||||
|
||||
// Remove a few pixels from the bottom offset so we get some overlap.
|
||||
dispatchMouseEvent(document, 'mousemove', elementRect.left, elementRect.bottom - 5);
|
||||
|
||||
Reference in New Issue
Block a user