Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 5ae1a85

Browse files
Ghislain BeaulacGhislain Beaulac
authored andcommitted
feat(filter): add slider unit tests
1 parent 4b952c9 commit 5ae1a85

File tree

5 files changed

+240
-8
lines changed

5 files changed

+240
-8
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import { JQueryUiSliderOption } from '../../models/jQueryUiSliderOption.interface';
2+
import { GridOption, FilterArguments, Column } from '../../models';
3+
import { Filters } from '..';
4+
import { SliderFilter } from '../sliderFilter';
5+
6+
const containerId = 'demo-container';
7+
8+
// define a <div> container to simulate the grid container
9+
const template = `<div id="${containerId}"></div>`;
10+
11+
const gridOptionMock = {
12+
enableFiltering: true,
13+
enableFilterTrimWhiteSpace: true,
14+
} as GridOption;
15+
16+
const gridStub = {
17+
getOptions: () => gridOptionMock,
18+
getColumns: jest.fn(),
19+
getHeaderRowColumn: jest.fn(),
20+
render: jest.fn(),
21+
};
22+
23+
describe('SliderFilter', () => {
24+
let divContainer: HTMLDivElement;
25+
let filter: SliderFilter;
26+
let filterArguments: FilterArguments;
27+
let spyGetHeaderRow;
28+
let mockColumn: Column;
29+
30+
beforeEach(() => {
31+
divContainer = document.createElement('div');
32+
divContainer.innerHTML = template;
33+
document.body.appendChild(divContainer);
34+
spyGetHeaderRow = jest.spyOn(gridStub, 'getHeaderRowColumn').mockReturnValue(divContainer);
35+
36+
mockColumn = { id: 'duration', field: 'duration', filterable: true, filter: { model: Filters.slider } };
37+
filterArguments = {
38+
grid: gridStub,
39+
columnDef: mockColumn,
40+
callback: jest.fn()
41+
};
42+
43+
filter = new SliderFilter();
44+
});
45+
46+
afterEach(() => {
47+
filter.destroy();
48+
});
49+
50+
it('should throw an error when trying to call init without any arguments', () => {
51+
expect(() => filter.init(null)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.');
52+
});
53+
54+
it('should initialize the filter', () => {
55+
filter.init(filterArguments);
56+
const filterCount = divContainer.querySelectorAll('.search-filter.slider-container.filter-duration').length;
57+
58+
expect(spyGetHeaderRow).toHaveBeenCalled();
59+
expect(filterCount).toBe(1);
60+
});
61+
62+
it('should call "setValues" and expect that value to be in the callback when triggered', () => {
63+
const spyCallback = jest.spyOn(filterArguments, 'callback');
64+
65+
filter.init(filterArguments);
66+
filter.setValues(['2']);
67+
const filterElm = divContainer.querySelector('.search-filter.slider-container.filter-duration');
68+
filterElm.dispatchEvent(new CustomEvent('change'));
69+
70+
expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['2'], shouldTriggerQuery: true });
71+
});
72+
73+
it('should call "setValues" and expect that value, converted as a string, to be in the callback when triggered', () => {
74+
const spyCallback = jest.spyOn(filterArguments, 'callback');
75+
76+
filter.init(filterArguments);
77+
filter.setValues(3);
78+
const filterElm = divContainer.querySelector('.search-filter.slider-container.filter-duration');
79+
filterElm.dispatchEvent(new CustomEvent('change'));
80+
const filterFilledElms = divContainer.querySelectorAll('.search-filter.slider-container.filter-duration.filled');
81+
82+
expect(filterFilledElms.length).toBe(1);
83+
expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['3'], shouldTriggerQuery: true });
84+
});
85+
86+
it('should call "setValues" with an empty string and not expect "filled" css class since it is empty', () => {
87+
const spyCallback = jest.spyOn(filterArguments, 'callback');
88+
89+
filter.init(filterArguments);
90+
filter.setValues('');
91+
const filterElm = divContainer.querySelector('.search-filter.slider-container.filter-duration');
92+
const filterFilledElms = divContainer.querySelectorAll('.search-filter.slider-container.filter-duration.filled');
93+
filterElm.dispatchEvent(new CustomEvent('change'));
94+
95+
expect(filterFilledElms.length).toBe(0);
96+
expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: [''], shouldTriggerQuery: true });
97+
});
98+
99+
it('should create the input filter with default search terms range when passed as a filter argument', () => {
100+
filterArguments.searchTerms = [3];
101+
102+
filter.init(filterArguments);
103+
const filterNumberElm = divContainer.querySelector<HTMLInputElement>('.input-group-text');
104+
const filterFilledElms = divContainer.querySelectorAll('.search-filter.slider-container.filter-duration.filled');
105+
106+
expect(filterFilledElms.length).toBe(1);
107+
expect(filterNumberElm.textContent).toBe('3');
108+
expect(filter.getValues()).toEqual(3);
109+
});
110+
111+
it('should create the input filter with default search terms and a different step size when "valueStep" is provided', () => {
112+
filterArguments.searchTerms = [15];
113+
mockColumn.filter.valueStep = 5;
114+
115+
filter.init(filterArguments);
116+
const filterNumberElm = divContainer.querySelector<HTMLInputElement>('.input-group-text');
117+
const filterInputElm = divContainer.querySelector<HTMLInputElement>('.search-filter.slider-container.filter-duration input');
118+
119+
expect(filterInputElm.step).toBe('5');
120+
expect(filterNumberElm.textContent).toBe('15');
121+
expect(filter.getValues()).toEqual(15);
122+
});
123+
124+
it('should create the input filter with min slider values being set by filter "minValue"', () => {
125+
mockColumn.filter = {
126+
minValue: 4,
127+
maxValue: 69,
128+
};
129+
130+
filter.init(filterArguments);
131+
132+
const filterNumberElm = divContainer.querySelector<HTMLInputElement>('.input-group-text');
133+
134+
expect(filterNumberElm.textContent).toBe('4');
135+
expect(filter.getValues()).toEqual(4);
136+
});
137+
138+
it('should create the input filter with min/max slider values being set by filter "sliderStartValue" and "sliderEndValue" through the filter params', () => {
139+
mockColumn.filter = {
140+
params: {
141+
sliderStartValue: 4,
142+
sliderEndValue: 69,
143+
}
144+
};
145+
146+
filter.init(filterArguments);
147+
148+
const filterNumberElm = divContainer.querySelector<HTMLInputElement>('.input-group-text');
149+
150+
expect(filterNumberElm.textContent).toBe('4');
151+
expect(filter.getValues()).toEqual(4);
152+
});
153+
154+
it('should create the input filter with default search terms range but without showing side numbers when "hideSliderNumber" is set in params', () => {
155+
filterArguments.searchTerms = [3];
156+
mockColumn.filter.params = { hideSliderNumber: true };
157+
158+
filter.init(filterArguments);
159+
160+
const filterNumberElms = divContainer.querySelectorAll<HTMLInputElement>('.input-group-text');
161+
162+
expect(filterNumberElms.length).toBe(0);
163+
expect(filter.getValues()).toEqual(3);
164+
});
165+
166+
it('should trigger a callback with the clear filter set when calling the "clear" method', () => {
167+
filterArguments.searchTerms = [3];
168+
const spyCallback = jest.spyOn(filterArguments, 'callback');
169+
170+
filter.init(filterArguments);
171+
filter.clear();
172+
173+
expect(filter.getValues()).toBe(0);
174+
expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: true });
175+
});
176+
177+
it('should trigger a callback with the clear filter but without querying when when calling the "clear" method with False as argument', () => {
178+
filterArguments.searchTerms = [3];
179+
const spyCallback = jest.spyOn(filterArguments, 'callback');
180+
181+
filter.init(filterArguments);
182+
filter.clear(false);
183+
184+
expect(filter.getValues()).toBe(0);
185+
expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false });
186+
});
187+
188+
it('should trigger a callback with the clear filter set when calling the "clear" method and expect min slider values being with values of "sliderStartValue" when defined through the filter params', () => {
189+
const spyCallback = jest.spyOn(filterArguments, 'callback');
190+
mockColumn.filter = {
191+
params: {
192+
sliderStartValue: 4,
193+
sliderEndValue: 69,
194+
}
195+
};
196+
197+
filter.init(filterArguments);
198+
filter.clear(false);
199+
200+
expect(filter.getValues()).toEqual(4);
201+
expect(spyCallback).toHaveBeenLastCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false });
202+
});
203+
});

src/app/modules/angular-slickgrid/filters/__tests__/sliderRangeFilter.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('SliderRangeFilter', () => {
5151
expect(() => filter.init(null)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.');
5252
});
5353

54-
it('should throw an error when trying override the slider "change" method', (done) => {
54+
it('should throw an error when trying to override the slider "change" method', (done) => {
5555
try {
5656
mockColumn.filter.filterOptions = { change: () => { } } as JQueryUiSliderOption;
5757
filter.init(filterArguments);
@@ -61,7 +61,7 @@ describe('SliderRangeFilter', () => {
6161
}
6262
});
6363

64-
it('should throw an error when trying override the slider "slide" method', (done) => {
64+
it('should throw an error when trying to override the slider "slide" method', (done) => {
6565
try {
6666
mockColumn.filter.filterOptions = { slide: () => { } } as JQueryUiSliderOption;
6767
filter.init(filterArguments);

src/app/modules/angular-slickgrid/filters/nativeSelectFilter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export class NativeSelectFilter implements Filter {
116116
}
117117

118118
/**
119-
* Get selected values retrieved from the multiple-selected element
119+
* Get selected values retrieved from the select element
120120
* @params selected items
121121
*/
122122
getValues(): any[] {

src/app/modules/angular-slickgrid/filters/sliderFilter.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const DEFAULT_STEP = 1;
1818

1919
export class SliderFilter implements Filter {
2020
private _clearFilterTriggered = false;
21+
private _currentValue: number;
2122
private _shouldTriggerQuery = true;
2223
private _elementRangeInputId: string;
2324
private _elementRangeOutputId: string;
@@ -70,6 +71,8 @@ export class SliderFilter implements Filter {
7071
// also add/remove "filled" class for styling purposes
7172
this.$filterElm.change((e: any) => {
7273
const value = e && e.target && e.target.value || '';
74+
this._currentValue = +value;
75+
7376
if (this._clearFilterTriggered) {
7477
this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
7578
this.$filterElm.removeClass('filled');
@@ -103,8 +106,10 @@ export class SliderFilter implements Filter {
103106
this._shouldTriggerQuery = shouldTriggerQuery;
104107
this.searchTerms = [];
105108
const clearedValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : DEFAULT_MIN_VALUE;
109+
this._currentValue = clearedValue;
106110
this.$filterElm.children('input').val(clearedValue);
107111
this.$filterElm.children('div.input-group-addon.input-group-append').children().html(clearedValue);
112+
this.$filterElm.val(clearedValue);
108113
this.$filterElm.trigger('change');
109114
}
110115
}
@@ -118,12 +123,24 @@ export class SliderFilter implements Filter {
118123
}
119124
}
120125

126+
/**
127+
* Get selected value retrieved from the slider element
128+
* @params selected items
129+
*/
130+
getValues(): number {
131+
return this._currentValue;
132+
}
133+
121134
/**
122135
* Set value(s) on the DOM element
123136
*/
124-
setValues(values: SearchTerm) {
125-
if (values) {
137+
setValues(values: SearchTerm | SearchTerm[]) {
138+
if (Array.isArray(values)) {
139+
this.$filterElm.val(values[0]);
140+
this._currentValue = +values[0];
141+
} else if (values) {
126142
this.$filterElm.val(values);
143+
this._currentValue = +values;
127144
}
128145
}
129146

@@ -143,7 +160,7 @@ export class SliderFilter implements Filter {
143160

144161
if (this.filterParams.hideSliderNumber) {
145162
return `
146-
<div class="search-filter filter-${fieldId}">
163+
<div class="search-filter slider-container filter-${fieldId}">
147164
<input type="range" id="${this._elementRangeInputId}"
148165
name="${this._elementRangeInputId}"
149166
defaultValue="${defaultValue}" min="${minValue}" max="${maxValue}" step="${step}"
@@ -152,7 +169,7 @@ export class SliderFilter implements Filter {
152169
}
153170

154171
return `
155-
<div class="input-group search-filter filter-${fieldId}">
172+
<div class="input-group slider-container search-filter filter-${fieldId}">
156173
<input type="range" id="${this._elementRangeInputId}"
157174
name="${this._elementRangeInputId}"
158175
defaultValue="${defaultValue}" min="${minValue}" max="${maxValue}" step="${step}"
@@ -170,12 +187,21 @@ export class SliderFilter implements Filter {
170187
*/
171188
private createDomElement(filterTemplate: string, searchTerm?: SearchTerm) {
172189
const fieldId = this.columnDef && this.columnDef.id;
190+
const minValue = this.filterProperties.hasOwnProperty('minValue') ? this.filterProperties.minValue : DEFAULT_MIN_VALUE;
191+
const startValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue;
173192
const $headerElm = this.grid.getHeaderRowColumn(fieldId);
174193
$($headerElm).empty();
175194

176195
// create the DOM element & add an ID and filter class
177196
const $filterElm = $(filterTemplate);
178-
const searchTermInput = (searchTerm || '0') as string;
197+
let searchTermInput = (searchTerm || '0') as string;
198+
if (+searchTermInput < minValue) {
199+
searchTermInput = `${minValue}`;
200+
}
201+
if (+searchTermInput < startValue) {
202+
searchTermInput = `${startValue}`;
203+
}
204+
this._currentValue = +searchTermInput;
179205

180206
$filterElm.children('input').val(searchTermInput);
181207
$filterElm.children('div.input-group-addon.input-group-append').children().html(searchTermInput);

src/app/modules/angular-slickgrid/models/filter.interface.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ export interface Filter {
3838
/** Destroy filter function */
3939
destroy: () => void;
4040

41+
/** Get value(s) of the DOM element */
42+
getValues?: (values: SearchTerm | SearchTerm[] | undefined) => void;
43+
4144
/** Set value(s) on the DOM element */
4245
setValues: (values: SearchTerm | SearchTerm[] | undefined) => void;
4346
}

0 commit comments

Comments
 (0)