clr-angular-static-fix
Version:
1. Install Clarity Icons package through npm:
518 lines (441 loc) • 19.2 kB
text/typescript
/*
* Copyright (c) 2016-2018 VMware, Inc. All Rights Reserved.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
import { TrackByFunction } from '@angular/core';
import { fakeAsync, tick } from '@angular/core/testing';
import { Subject } from 'rxjs';
import { ClrDatagridFilterInterface } from '../interfaces/filter.interface';
import { FiltersProvider } from './filters';
import { Items } from './items';
import { Page } from './page';
import { Selection, SelectionType } from './selection';
import { Sort } from './sort';
import { StateDebouncer } from './state-debouncer.provider';
const numberSort = (a: number, b: number) => a - b;
export default function(): void {
let selectionInstance: Selection;
let sortInstance: Sort;
let pageInstance: Page;
let filtersInstance: FiltersProvider;
let itemsInstance: Items;
describe('Selection provider', function() {
beforeEach(function() {
const stateDebouncer = new StateDebouncer();
pageInstance = new Page(stateDebouncer);
filtersInstance = new FiltersProvider(pageInstance, stateDebouncer);
sortInstance = new Sort(stateDebouncer);
itemsInstance = new Items(filtersInstance, sortInstance, pageInstance);
selectionInstance = new Selection(itemsInstance, filtersInstance);
});
afterEach(function() {
selectionInstance.destroy();
itemsInstance.destroy();
});
describe('with smart items', function() {
beforeEach(function() {
itemsInstance.smartenUp();
itemsInstance.all = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
});
it('starts inactive', function() {
expect(selectionInstance.selectionType).toBe(SelectionType.None);
expect(selectionInstance.current).toBeUndefined();
selectionInstance.setSelected(4, true);
expect(selectionInstance.current).toBeUndefined();
});
it('can select/deselect items in multi selection type', function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.setSelected(4, true);
expect(selectionInstance.current).toEqual([4]);
selectionInstance.setSelected(2, true);
expect(selectionInstance.current).toEqual([4, 2]);
});
it('can select/deselect all items at once in multi selection type', function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual(itemsInstance.displayed);
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual([]);
selectionInstance.setSelected(4, true);
expect(selectionInstance.current).toEqual([4]);
selectionInstance.toggleAll();
expect(selectionInstance.current.sort(numberSort)).toEqual(itemsInstance.displayed);
});
it("can't select/deselect all items at once in other single selection type", function() {
selectionInstance.selectionType = SelectionType.Single;
selectionInstance.toggleAll();
expect(selectionInstance.currentSingle).toBeUndefined();
selectionInstance.currentSingle = 4;
selectionInstance.toggleAll();
expect(selectionInstance.currentSingle).toEqual(4);
});
it('can select/deselect all items at once in multi selection type if no pagination exist', function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual(itemsInstance.displayed);
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual([]);
selectionInstance.setSelected(4, true);
expect(selectionInstance.current).toEqual([4]);
selectionInstance.toggleAll();
expect(selectionInstance.current.sort(numberSort)).toEqual(itemsInstance.displayed);
});
it('can select/deselect items only on the current page', function() {
selectionInstance.selectionType = SelectionType.Multi;
pageInstance.size = 3;
selectionInstance.current = [4, 1, 2];
pageInstance.current = 2;
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual([4, 1, 2, 5, 6]);
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual([1, 2]);
});
it("can't select/deselect all items at once in other single selection type", function() {
selectionInstance.selectionType = SelectionType.Single;
selectionInstance.toggleAll();
expect(selectionInstance.currentSingle).toBeUndefined();
selectionInstance.currentSingle = 4;
selectionInstance.toggleAll();
expect(selectionInstance.currentSingle).toEqual(4);
});
it('can detect if an item is selected', function() {
selectionInstance.selectionType = SelectionType.Multi;
expect(selectionInstance.isSelected(4)).toBe(false);
selectionInstance.setSelected(4, true);
expect(selectionInstance.isSelected(4)).toBe(true);
selectionInstance.setSelected(4, false);
expect(selectionInstance.isSelected(4)).toBe(false);
});
it('can detect if all items are selected in multi selection type', function() {
selectionInstance.selectionType = SelectionType.Multi;
expect(selectionInstance.isAllSelected()).toBe(false);
selectionInstance.setSelected(4, true);
expect(selectionInstance.isAllSelected()).toBe(false);
selectionInstance.current = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
expect(selectionInstance.isAllSelected()).toBe(true);
});
it('accepts pre-selected items in multi selection type', function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.current = [4, 2];
expect(selectionInstance.isSelected(1)).toBe(false);
expect(selectionInstance.isSelected(2)).toBe(true);
expect(selectionInstance.isSelected(3)).toBe(false);
expect(selectionInstance.isSelected(4)).toBe(true);
});
it('accepts pre-selected item in single selection type', function() {
selectionInstance.selectionType = SelectionType.Single;
selectionInstance.currentSingle = 2;
expect(selectionInstance.isSelected(1)).toBe(false);
expect(selectionInstance.isSelected(2)).toBe(true);
expect(selectionInstance.isSelected(3)).toBe(false);
expect(selectionInstance.isSelected(4)).toBe(false);
});
it('exposes an Observable to follow selection changes in multi selection type', function() {
let nbChanges = 0;
let currentSelection: any[];
selectionInstance.change.subscribe((items: any[]) => {
nbChanges++;
currentSelection = items;
});
expect(currentSelection).toBeUndefined();
selectionInstance.selectionType = SelectionType.Multi;
expect(currentSelection).toEqual([]);
selectionInstance.setSelected(4, true);
expect(selectionInstance.current).toEqual([4]);
selectionInstance.toggleAll();
expect(selectionInstance.current.sort(numberSort)).toEqual(itemsInstance.displayed);
selectionInstance.toggleAll();
expect(selectionInstance.current).toEqual([]);
expect(nbChanges).toBe(4);
});
it('exposes an Observable to follow selection changes in single selection type', function() {
let nbChanges = 0;
let currentSelection: any;
selectionInstance.change.subscribe((items: any) => {
nbChanges++;
currentSelection = items;
});
expect(currentSelection).toBeUndefined();
selectionInstance.selectionType = SelectionType.Single;
expect(currentSelection).toBeUndefined();
selectionInstance.currentSingle = 4;
selectionInstance.currentSingle = 2;
expect(nbChanges).toBe(3);
});
it('does not emit selection change twice after a filter is applied', function() {
let nbChanges = 0;
let currentSelection: any;
selectionInstance.change.subscribe((items: any) => {
nbChanges++;
currentSelection = items;
});
selectionInstance.selectionType = SelectionType.Multi;
expect(nbChanges).toBe(1); // current is initialized to [] at this point
selectionInstance.current = [4, 2];
expect(nbChanges).toBe(2);
const evenFilter: EvenFilter = new EvenFilter();
filtersInstance.add(<ClrDatagridFilterInterface<any>>evenFilter);
evenFilter.toggle();
// current is set to [] because filter is applied, and nbChanges is 3.
// there isn't an additional change that would have been fired to
// update current selection given the new data set post filter.
expect(selectionInstance.current.length).toBe(0);
expect(nbChanges).toBe(3);
});
it('clears selection when a filter is added', function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.current = [4, 2];
const evenFilter: EvenFilter = new EvenFilter();
filtersInstance.add(<ClrDatagridFilterInterface<any>>evenFilter);
evenFilter.toggle();
expect(selectionInstance.current.length).toBe(0);
});
it(
'keeps only the remaining selection when the items are updated',
fakeAsync(function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.current = [4, 2];
itemsInstance.all = [1, 2, 3, 5];
tick();
expect(selectionInstance.current.length).toBe(1);
expect(selectionInstance.current).toEqual([2]);
})
);
it(
'keeps all the selections when the items are updated ' + 'and the contain all the previous selection',
fakeAsync(function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.current = [4, 2];
itemsInstance.all = [1, 2, 3, 4, 5];
tick();
expect(selectionInstance.current.length).toBe(2);
expect(selectionInstance.current).toEqual([4, 2]);
})
);
it(
'clears the selections when the items are updated and ' + 'they do not contain the previous selection',
fakeAsync(function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.current = [4, 2];
itemsInstance.all = [1, 3, 5];
tick();
expect(selectionInstance.current.length).toBe(0);
expect(selectionInstance.current).toEqual([]);
})
);
it('maintains the selection when the page is changed', function() {
selectionInstance.selectionType = SelectionType.Multi;
selectionInstance.current = [4, 2];
pageInstance.size = 3;
pageInstance.current = 2;
expect(selectionInstance.current).toEqual([4, 2]);
});
});
describe('client-side selection and pagination', function() {
const items = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
{ id: 5 },
{ id: 6 },
{ id: 7 },
{ id: 8 },
{ id: 9 },
{ id: 10 },
];
function cloneItems() {
return items.map(item => {
return { ...item };
});
}
function testSelectedItems(latestItems, selectedIndexes: any[]) {
latestItems.forEach((item, index) => {
const state = selectedIndexes.indexOf(index) > -1;
expect(selectionInstance.isSelected(item)).toEqual(state);
});
}
beforeEach(function() {
itemsInstance.smartenUp();
itemsInstance.all = items;
pageInstance.size = 3;
});
describe('multi-selection', function() {
beforeEach(function() {
selectionInstance.selectionType = SelectionType.Multi;
});
it('should preserve selection on page change', function() {
selectionInstance.setSelected(items[2], true);
expect(selectionInstance.current).toEqual([items[2]]);
pageInstance.current = 3;
expect(selectionInstance.current).toEqual([items[2]]);
});
function testTrackBy(trackBy: TrackByFunction<{ id: number }>) {
return fakeAsync(function() {
itemsInstance.trackBy = trackBy;
selectionInstance.setSelected(items[2], true);
const clones = cloneItems();
itemsInstance.all = clones;
tick();
expect(selectionInstance.current).toEqual([clones[2]]);
testSelectedItems(clones, [2]);
});
}
it('should support trackBy item', testTrackBy((index, item) => item.id));
it('should support trackBy index', testTrackBy((index, item) => index));
});
describe('single selection', function() {
beforeEach(function() {
selectionInstance.selectionType = SelectionType.Single;
});
it('should preserve selection on page change', function() {
selectionInstance.currentSingle = items[2];
pageInstance.current = 2;
expect(selectionInstance.isSelected(items[2])).toBe(true);
selectionInstance.currentSingle = items[5];
pageInstance.current = 3;
expect(selectionInstance.isSelected(items[5])).toBe(true);
});
it(
'should clear selection if it is no longer in dataset',
fakeAsync(() => {
selectionInstance.currentSingle = items[2];
pageInstance.current = 2;
expect(selectionInstance.isSelected(items[2])).toBe(true);
itemsInstance.all = cloneItems().splice(2, 1);
tick();
expect(selectionInstance.currentSingle).toBe(undefined);
})
);
it('does not apply trackBy to single selection with no items', () => {
const emptyItems = new Items(filtersInstance, sortInstance, pageInstance);
const selection: Selection = new Selection(emptyItems, filtersInstance);
spyOn(emptyItems, 'trackBy');
expect(selection.currentSingle).toBeUndefined();
selection.currentSingle = items[2];
expect(emptyItems.trackBy).not.toHaveBeenCalled();
});
function testTrackBy(trackBy: TrackByFunction<{ id: number }>) {
return fakeAsync(function() {
itemsInstance.trackBy = trackBy;
selectionInstance.currentSingle = items[2];
const clones = cloneItems();
itemsInstance.all = clones;
tick();
testSelectedItems(clones, [2]);
});
}
it('should support trackBy item', testTrackBy((index, item) => item.id));
it('should support trackBy index', testTrackBy((index, item) => index));
});
});
describe('server-driven selection and pagination', function() {
const itemsA = [{ id: 1 }, { id: 2 }, { id: 3 }];
const itemsB = [{ id: 4 }, { id: 5 }, { id: 6 }];
const itemsC = itemsA.map(item => Object.assign({ modified: true }, item));
function testSelection(stateA, stateB, stateC) {
expect(selectionInstance.isSelected(itemsA[0])).toEqual(stateA);
expect(selectionInstance.isSelected(itemsB[0])).toEqual(stateB);
expect(selectionInstance.isSelected(itemsC[0])).toEqual(stateC);
}
function testToggleAllSelection(stateA, stateB, stateC) {
itemsA.forEach(element => {
expect(selectionInstance.isSelected(element)).toEqual(stateA);
});
itemsB.forEach(element => {
expect(selectionInstance.isSelected(element)).toEqual(stateB);
});
itemsC.forEach(element => {
expect(selectionInstance.isSelected(element)).toEqual(stateC);
});
}
describe('multi-selection', function() {
beforeEach(function() {
selectionInstance.selectionType = SelectionType.Multi;
});
// We don't support server-driven, multi-selection without trackBy.
// We don't support server-driven, multi-selection, trackBy index.
it(
'should support trackBy item',
fakeAsync(() => {
itemsInstance.trackBy = (index, item) => item.id;
itemsInstance.all = itemsA;
tick();
selectionInstance.setSelected(itemsA[0], true);
testSelection(true, false, false);
itemsInstance.all = itemsB;
tick();
testSelection(true, false, false);
itemsInstance.all = itemsC;
tick();
testSelection(false, false, true);
expect(selectionInstance.current[0].modified).toEqual(true);
})
);
it(
'should support toggleAll selection on page change',
fakeAsync(() => {
itemsInstance.trackBy = (index, item) => item.id;
itemsInstance.all = itemsA;
pageInstance.size = 3;
pageInstance.current = 1;
tick();
selectionInstance.toggleAll();
testToggleAllSelection(true, false, false);
itemsInstance.all = itemsB;
pageInstance.current = 2;
tick();
testToggleAllSelection(true, false, false);
itemsInstance.all = itemsC;
pageInstance.current = 1;
tick();
testToggleAllSelection(false, false, true);
expect(selectionInstance.current[0].modified).toEqual(true);
})
);
});
describe('single selection', function() {
beforeEach(function() {
selectionInstance.selectionType = SelectionType.Single;
});
// We don't support server-driven, multi-selection without trackBy.
// We don't support server-driven, multi-selection, trackBy index.
it(
'should support trackBy item',
fakeAsync(() => {
itemsInstance.trackBy = (index, item) => item.id;
itemsInstance.all = itemsA;
tick();
selectionInstance.currentSingle = itemsA[0];
testSelection(true, false, false);
itemsInstance.all = itemsB;
tick();
testSelection(true, false, false);
// itemsInstance.all = itemsC;
// tick();
// testSelection(false, false, true);
// expect(selectionInstance.currentSingle.modified).toEqual(true);
})
);
});
});
});
}
abstract class TestFilter implements ClrDatagridFilterInterface<number> {
private active = false;
toggle() {
this.active = !this.active;
this.changes.next(this.active);
}
isActive(): boolean {
return this.active;
}
changes = new Subject<boolean>();
abstract accepts(n: number): boolean;
}
class EvenFilter extends TestFilter {
accepts(n: number): boolean {
return n % 2 === 0;
}
}