Skip to content

Commit

Permalink
feat(core): add collectionAsync option for both the Editors & Filte…
Browse files Browse the repository at this point in the history
…rs (#16)

* feat: add `collectionAsync` option for both the Editors & Filters
  • Loading branch information
ghiscoding authored Jul 18, 2020
1 parent ebfd715 commit f9488ab
Show file tree
Hide file tree
Showing 13 changed files with 546 additions and 214 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ npm run test:watch
- [x] Dynamically Add Columns
- [x] Tree Data
- [ ] Translations Support
- [ ] add missing `collectionAsync` for Editors (maybe Filter too?)
- [x] add missing `collectionAsync` for Editors
- [x] add missing `collectionAsync` for Filters
- [x] requires updating each Filters supporting `collectionAsync` (autoCompleteFilter, selectFilter)
- [x] Grid Service should use SlickGrid transactions `beginUpdate`, `endUpdate` for performance reason whenever possible

#### Other Todos
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"workspaces": {
"packages": [
"examples/*",
"packages/*"
],
"nohoist": [
Expand Down
111 changes: 110 additions & 1 deletion packages/common/src/filters/__tests__/autoCompleteFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AutoCompleteFilter } from '../autoCompleteFilter';
import { FieldType, OperatorType } from '../../enums/index';
import { AutocompleteOption, Column, FilterArguments, GridOption, SlickGrid } from '../../interfaces/index';
import { CollectionService } from '../../services/collection.service';
import { HttpStub } from '../../../../../test/httpClientStub';
import { TranslateServiceStub } from '../../../../../test/translateServiceStub';

const containerId = 'demo-container';
Expand Down Expand Up @@ -30,6 +31,7 @@ describe('AutoCompleteFilter', () => {
let spyGetHeaderRow;
let mockColumn: Column;
let collectionService: CollectionService;
const http = new HttpStub();

beforeEach(() => {
translaterService = new TranslateServiceStub();
Expand Down Expand Up @@ -69,7 +71,7 @@ describe('AutoCompleteFilter', () => {
mockColumn.filter.collection = undefined;
filter.init(filterArguments);
} catch (e) {
expect(e.toString()).toContain(`[Slickgrid-Universal] You need to pass a "collection" for the AutoComplete Filter to work correctly.`);
expect(e.toString()).toContain(`[Slickgrid-Universal] You need to pass a "collection" (or "collectionAsync") for the AutoComplete Filter to work correctly.`);
done();
}
});
Expand All @@ -85,6 +87,14 @@ describe('AutoCompleteFilter', () => {
}
});

it('should throw an error when "collectionAsync" Promise does not return a valid array', (done) => {
mockColumn.filter.collectionAsync = Promise.resolve({ hello: 'world' });
filter.init(filterArguments).catch((e) => {
expect(e.toString()).toContain(`Something went wrong while trying to pull the collection from the "collectionAsync" call in the AutoComplete Filter, the collection is not a valid array.`);
done();
});
});

it('should initialize the filter', () => {
mockColumn.filter.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
filter.init(filterArguments);
Expand Down Expand Up @@ -241,6 +251,84 @@ describe('AutoCompleteFilter', () => {
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false });
});

it('should create the filter with a default search term when using "collectionAsync" as a Promise', (done) => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
const mockCollection = ['male', 'female'];
mockColumn.filter.collectionAsync = Promise.resolve(mockCollection);

filterArguments.searchTerms = ['female'];
filter.init(filterArguments);

setTimeout(() => {
const filterElm = divContainer.querySelector<HTMLInputElement>('input.filter-gender');
const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
filter.setValues('male');

filterElm.focus();
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));
const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');

expect(autocompleteUlElms.length).toBe(1);
expect(filterFilledElms.length).toBe(1);
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
done();
});
});

it('should create the filter with a default search term when using "collectionAsync" as a Promise with content to simulate http-client', (done) => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
const mockCollection = ['male', 'female'];
mockColumn.filter.collectionAsync = Promise.resolve({ content: mockCollection });

filterArguments.searchTerms = ['female'];
filter.init(filterArguments);

setTimeout(() => {
const filterElm = divContainer.querySelector<HTMLInputElement>('input.filter-gender');
const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
filter.setValues('male');

filterElm.focus();
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));
const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');

expect(autocompleteUlElms.length).toBe(1);
expect(filterFilledElms.length).toBe(1);
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
done();
});
});

it('should create the filter with a default search term when using "collectionAsync" is a Fetch Promise', (done) => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
const mockCollection = ['male', 'female'];

http.status = 200;
http.object = mockCollection;
http.returnKey = 'date';
http.returnValue = '6/24/1984';
http.responseHeaders = { accept: 'json' };
mockColumn.filter.collectionAsync = http.fetch('/api', { method: 'GET' });

filterArguments.searchTerms = ['female'];
filter.init(filterArguments);

setTimeout(() => {
const filterElm = divContainer.querySelector<HTMLInputElement>('input.filter-gender');
const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
filter.setValues('male');

filterElm.focus();
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));
const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');

expect(autocompleteUlElms.length).toBe(1);
expect(filterFilledElms.length).toBe(1);
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
done();
});
});

it('should create the filter and filter the string collection when "collectionFilterBy" is set', () => {
mockColumn.filter = {
collection: ['other', 'male', 'female'],
Expand Down Expand Up @@ -307,6 +395,27 @@ describe('AutoCompleteFilter', () => {
expect(filterCollection[2]).toEqual({ value: 'female', description: 'female' });
});

it('should create the filter with a value/label pair collectionAsync that is inside an object when "collectionInsideObjectProperty" is defined with a dot notation', (done) => {
const mockCollection = { deep: { myCollection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }] } };
mockColumn.filter = {
collectionAsync: Promise.resolve(mockCollection),
collectionOptions: { collectionInsideObjectProperty: 'deep.myCollection' },
customStructure: { value: 'value', label: 'description', },
};

filter.init(filterArguments);

setTimeout(() => {
const filterCollection = filter.collection;

expect(filterCollection.length).toBe(3);
expect(filterCollection[0]).toEqual({ value: 'other', description: 'other' });
expect(filterCollection[1]).toEqual({ value: 'male', description: 'male' });
expect(filterCollection[2]).toEqual({ value: 'female', description: 'female' });
done();
}, 2);
});

it('should create the filter and sort the string collection when "collectionSortBy" is set', () => {
mockColumn.filter = {
collection: ['other', 'male', 'female'],
Expand Down
Loading

0 comments on commit f9488ab

Please sign in to comment.