diff --git a/examples/vite-demo-vanilla-bundle/src/app-routing.ts b/examples/vite-demo-vanilla-bundle/src/app-routing.ts
index 32159c197..04a10e803 100644
--- a/examples/vite-demo-vanilla-bundle/src/app-routing.ts
+++ b/examples/vite-demo-vanilla-bundle/src/app-routing.ts
@@ -25,6 +25,7 @@ import Example21 from './examples/example21';
import Example22 from './examples/example22';
import Example23 from './examples/example23';
import Example24 from './examples/example24';
+import Example25 from './examples/example25';
export class AppRouting {
constructor(private config: RouterConfig) {
@@ -55,6 +56,7 @@ export class AppRouting {
{ route: 'example22', name: 'example22', view: './examples/example22.html', viewModel: Example22, title: 'Example22', },
{ route: 'example23', name: 'example23', view: './examples/example23.html', viewModel: Example23, title: 'Example23', },
{ route: 'example24', name: 'example24', view: './examples/example24.html', viewModel: Example24, title: 'Example24', },
+ { route: 'example25', name: 'example25', view: './examples/example25.html', viewModel: Example25, title: 'Example25', },
{ route: '', redirect: 'example01' },
{ route: '**', redirect: 'example01' }
];
diff --git a/examples/vite-demo-vanilla-bundle/src/app.html b/examples/vite-demo-vanilla-bundle/src/app.html
index ab3a34936..e77eaa25f 100644
--- a/examples/vite-demo-vanilla-bundle/src/app.html
+++ b/examples/vite-demo-vanilla-bundle/src/app.html
@@ -108,6 +108,9 @@
Slickgrid-Universal
Example24 - Footer Totals Row
+
+ Example25 - Range Filters
+
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example21.html b/examples/vite-demo-vanilla-bundle/src/examples/example21.html
index 8984dc1f3..1c4684cda 100644
--- a/examples/vite-demo-vanilla-bundle/src/examples/example21.html
+++ b/examples/vite-demo-vanilla-bundle/src/examples/example21.html
@@ -18,7 +18,7 @@
-
+
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example25.html b/examples/vite-demo-vanilla-bundle/src/examples/example25.html
new file mode 100644
index 000000000..d3fe92f7b
--- /dev/null
+++ b/examples/vite-demo-vanilla-bundle/src/examples/example25.html
@@ -0,0 +1,46 @@
+
+ Example 25 - Range Filters
+
+
+
+
+
+ Metrics:
+
+ of
+ items
+
+
+
+
+
+
+
+
+
+
+ Locale:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example25.ts b/examples/vite-demo-vanilla-bundle/src/examples/example25.ts
new file mode 100644
index 000000000..c341e633e
--- /dev/null
+++ b/examples/vite-demo-vanilla-bundle/src/examples/example25.ts
@@ -0,0 +1,283 @@
+import { addDay, format } from '@formkit/tempo';
+
+import { SlickCustomTooltip } from '@slickgrid-universal/custom-tooltip-plugin';
+import { ExcelExportService } from '@slickgrid-universal/excel-export';
+import { Slicker, type SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle';
+
+import {
+ type Column,
+ type CurrentFilter,
+ FieldType,
+ Filters,
+ Formatters,
+ type GridOption,
+ type GridStateChange,
+ type MultipleSelectOption,
+ OperatorType,
+ type SliderRangeOption,
+} from '@slickgrid-universal/common';
+import { BindingEventService } from '@slickgrid-universal/binding';
+
+import { ExampleGridOptions } from './example-grid-options';
+import { type TranslateService } from '../translate.service';
+
+const NB_ITEMS = 5000;
+
+function randomBetween(min: number, max: number): number {
+ return Math.floor(Math.random() * (max - min + 1) + min);
+}
+
+export default class Example25 {
+ private _bindingEventService: BindingEventService;
+ columnDefinitions: Column[] = [];
+ gridContainerElm: HTMLDivElement;
+ gridOptions!: GridOption;
+ dataset: any[] = [];
+ metricsEndTime = '';
+ metricsStartTime = '';
+ metricsItemCount = 0;
+ metricsTotalItemCount = 0;
+ filterList = [
+ { value: '', label: '' },
+ { value: 'currentYearTasks', label: 'Current Year Completed Tasks' },
+ { value: 'nextYearTasks', label: 'Next Year Active Tasks' }
+ ];
+ selectedLanguage = 'en';
+ selectedLanguageFile = 'en.json';
+ sgb: SlickVanillaGridBundle;
+ translateService: TranslateService;
+
+ constructor() {
+ this._bindingEventService = new BindingEventService();
+
+ // get the Translate Service from the window object,
+ // it might be better with proper Dependency Injection but this project doesn't have any at this point
+ this.translateService = (
window).TranslateService;
+ }
+
+ attached() {
+ // define the grid options & columns and then create the grid itself
+ this.defineGrid();
+
+ // mock some data (different in each dataset)
+ this.dataset = this.mockData(NB_ITEMS);
+ this.gridContainerElm = document.querySelector('.grid25') as HTMLDivElement;
+
+ this.sgb = new Slicker.GridBundle(this.gridContainerElm, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, this.dataset);
+
+ // bind any of the grid events
+ this._bindingEventService.bind(this.gridContainerElm, 'ongridstatechanged', this.gridStateChanged.bind(this));
+ this._bindingEventService.bind(this.gridContainerElm, 'onrowcountchanged', this.refreshMetrics.bind(this));
+
+ this.metricsEndTime = format(new Date(), 'DD MMM, h:mm:ss a');
+ this.metricsStartTime = format(new Date(), 'DD MMM, h:mm:ss a');
+ this.metricsItemCount = this.sgb.dataView?.getFilteredItemCount() || 0;
+ this.metricsTotalItemCount = this.dataset.length || 0;
+
+ document.body.classList.add('material-theme');
+ }
+
+ dispose() {
+ this.saveCurrentGridState();
+ document.body.classList.remove('material-theme');
+ }
+
+ /* Define grid Options and Columns */
+ defineGrid() {
+ this.columnDefinitions = [
+ {
+ id: 'title', name: 'Title', field: 'id', nameKey: 'TITLE', minWidth: 100,
+ formatter: (_row, _cell, value) => {
+ return this.translateService.translate('TASK_X', { x: value }) ?? '';
+ },
+ sortable: true,
+ filterable: true,
+ params: { useFormatterOuputToFilter: true }
+ },
+ {
+ id: 'description', name: 'Description', field: 'description', filterable: true, sortable: true, minWidth: 80,
+ type: FieldType.string,
+ },
+ {
+ id: 'percentComplete', name: '% Complete', field: 'percentComplete', nameKey: 'PERCENT_COMPLETE', minWidth: 120,
+ sortable: true,
+ customTooltip: { position: 'center' },
+ formatter: Formatters.progressBar,
+ type: FieldType.number,
+ filterable: true,
+ filter: {
+ model: Filters.sliderRange,
+ maxValue: 100, // or you can use the filterOptions as well
+ operator: OperatorType.rangeInclusive, // defaults to inclusive
+ filterOptions: {
+ hideSliderNumbers: false, // you can hide/show the slider numbers on both side
+ min: 0, step: 5
+ } as SliderRangeOption
+ }
+ },
+ {
+ id: 'start', name: 'Start', field: 'start', nameKey: 'START', formatter: Formatters.dateIso, sortable: true, minWidth: 75, width: 100, exportWithFormatter: true,
+ type: FieldType.date, filterable: true, filter: { model: Filters.compoundDate }
+ },
+ {
+ id: 'finish', name: 'Finish', field: 'finish', nameKey: 'FINISH', formatter: Formatters.dateIso, sortable: true, minWidth: 75, width: 120, exportWithFormatter: true,
+ type: FieldType.date,
+ filterable: true,
+ filter: {
+ model: Filters.dateRange,
+ }
+ },
+ {
+ id: 'duration', field: 'duration', nameKey: 'DURATION', maxWidth: 90,
+ type: FieldType.number,
+ sortable: true,
+ filterable: true, filter: {
+ model: Filters.input,
+ operator: OperatorType.rangeExclusive // defaults to exclusive
+ }
+ },
+ {
+ id: 'completed', name: 'Completed', field: 'completed', nameKey: 'COMPLETED', minWidth: 85, maxWidth: 90,
+ formatter: Formatters.checkmarkMaterial,
+ exportWithFormatter: true, // you can set this property in the column definition OR in the grid options, column def has priority over grid options
+ filterable: true,
+ filter: {
+ collection: [{ value: '', label: '' }, { value: true, label: 'True' }, { value: false, label: 'False' }],
+ model: Filters.singleSelect,
+ filterOptions: { autoAdjustDropHeight: true } as MultipleSelectOption
+ }
+ }
+ ];
+
+ const today = new Date();
+ const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD');
+ const presetHighestDay = format(addDay(new Date(), today.getDate() < 14 ? 30 : 25), 'YYYY-MM-DD');
+
+ this.gridOptions = {
+ autoResize: {
+ container: '.demo-container',
+ },
+ enableExcelCopyBuffer: true,
+ enableFiltering: true,
+ enableTranslate: true,
+ translater: this.translateService, // pass the TranslateService instance to the grid
+
+ // use columnDef searchTerms OR use presets as shown below
+ presets: {
+ filters: [
+ // you can use the 2 dots separator on all Filters which support ranges
+ { columnId: 'duration', searchTerms: ['4..88'] },
+ // { columnId: 'percentComplete', searchTerms: ['5..80'] }, // without operator will default to 'RangeExclusive'
+ // { columnId: 'finish', operator: 'RangeInclusive', searchTerms: [`${presetLowestDay}..${presetHighestDay}`] },
+
+ // or you could also use 2 searchTerms values, instead of using the 2 dots (only works with SliderRange & DateRange Filters)
+ // BUT make sure to provide the operator, else the filter service won't know that this is really a range
+ { columnId: 'percentComplete', operator: 'RangeInclusive', searchTerms: [5, 80] }, // same result with searchTerms: ['5..80']
+ { columnId: 'finish', operator: 'RangeInclusive', searchTerms: [presetLowestDay, presetHighestDay] },
+ ],
+ sorters: [
+ { columnId: 'percentComplete', direction: 'DESC' },
+ { columnId: 'duration', direction: 'ASC' },
+ ],
+ },
+ externalResources: [new SlickCustomTooltip(), new ExcelExportService()],
+ };
+ }
+
+ mockData(itemCount: number, startingIndex = 0): any[] {
+ // mock a dataset
+ const tempDataset: any[] = [];
+ for (let i = startingIndex; i < (startingIndex + itemCount); i++) {
+ const randomDuration = randomBetween(0, 365);
+ const randomYear = randomBetween(new Date().getFullYear(), new Date().getFullYear() + 1);
+ const randomMonth = randomBetween(0, 12);
+ const randomDay = randomBetween(10, 28);
+ const randomPercent = randomBetween(0, 100);
+
+ tempDataset.push({
+ id: i,
+ title: 'Task ' + i,
+ description: (i % 5) ? 'desc ' + i : null, // also add some random to test NULL field
+ duration: randomDuration,
+ percentComplete: randomPercent,
+ percentCompleteNumber: randomPercent,
+ start: (i % 4) ? null : new Date(randomYear, randomMonth, randomDay), // provide a Date format
+ finish: new Date(randomYear, randomMonth, randomDay),
+ completed: (randomPercent === 100) ? true : false,
+ });
+ }
+
+ return tempDataset;
+ }
+
+ clearFilters() {
+ this.sgb?.filterService.clearFilters();
+ }
+
+ /** Dispatched event of a Grid State Changed event */
+ gridStateChanged(event) {
+ if (event?.detail) {
+ console.log('Client sample, Grid State changed:: ', event.detail as GridStateChange);
+ }
+ }
+
+ /** Save current Filters, Sorters in LocaleStorage or DB */
+ saveCurrentGridState() {
+ console.log('Client sample, current Grid State:: ', this.sgb?.gridStateService.getCurrentGridState());
+ }
+
+ refreshMetrics(event) {
+ const args = event?.detail?.args;
+ if (args?.current >= 0) {
+ this.metricsStartTime = format(new Date(), 'DD MMM, h:mm:ss a');
+ this.metricsItemCount = args?.current || 0;
+ this.metricsTotalItemCount = this.dataset.length || 0;
+ }
+ }
+
+ setFiltersDynamically() {
+ const presetLowestDay = format(addDay(new Date(), -5), 'YYYY-MM-DD');
+ const presetHighestDay = format(addDay(new Date(), 25), 'YYYY-MM-DD');
+
+ // we can Set Filters Dynamically (or different filters) afterward through the FilterService
+ this.sgb.filterService.updateFilters([
+ { columnId: 'duration', searchTerms: ['14..78'], operator: 'RangeInclusive' },
+ { columnId: 'percentComplete', operator: 'RangeExclusive', searchTerms: [15, 85] },
+ { columnId: 'start', operator: '<=', searchTerms: [presetHighestDay] },
+ { columnId: 'finish', operator: 'RangeInclusive', searchTerms: [presetLowestDay, presetHighestDay] },
+ ]);
+ }
+
+ setSortingDynamically() {
+ this.sgb?.sortService.updateSorting([
+ // orders matter, whichever is first in array will be the first sorted column
+ { columnId: 'finish', direction: 'DESC' },
+ { columnId: 'percentComplete', direction: 'ASC' },
+ ]);
+ }
+
+ predefinedFilterChanged(newPredefinedFilter: string) {
+ let filters: CurrentFilter[] = [];
+ const currentYear = new Date().getFullYear();
+
+ switch (newPredefinedFilter) {
+ case 'currentYearTasks':
+ filters = [
+ { columnId: 'finish', operator: OperatorType.rangeInclusive, searchTerms: [`${currentYear}-01-01`, `${currentYear}-12-31`] },
+ { columnId: 'completed', operator: OperatorType.equal, searchTerms: [true] },
+ ];
+ break;
+ case 'nextYearTasks':
+ filters = [{ columnId: 'start', operator: '>=', searchTerms: [`${currentYear + 1}-01-01`] }];
+ break;
+ }
+ this.sgb?.filterService.updateFilters(filters);
+ }
+
+ async switchLanguage() {
+ const nextLanguage = (this.selectedLanguage === 'en') ? 'fr' : 'en';
+ await this.translateService.use(nextLanguage);
+ this.selectedLanguage = nextLanguage;
+ this.selectedLanguageFile = `${this.selectedLanguage}.json`;
+ }
+}
diff --git a/packages/common/src/filters/dateFilter.ts b/packages/common/src/filters/dateFilter.ts
index 4f41c7872..2fac06b01 100644
--- a/packages/common/src/filters/dateFilter.ts
+++ b/packages/common/src/filters/dateFilter.ts
@@ -227,7 +227,6 @@ export class DateFilter implements Filter {
if (this.calendarInstance && pickerValues !== undefined) {
setPickerDates(this.columnFilter, this._dateInputElm, this.calendarInstance, {
columnDef: this.columnDef,
- oldVal: this._currentDateOrDates,
newVal: pickerValues,
updatePickerUI: true
});
diff --git a/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts b/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts
index 298a6dca8..557c966b7 100644
--- a/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts
+++ b/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts
@@ -303,7 +303,7 @@ export class SlickVanillaGridBundle {
) {
// make sure that the grid container doesn't already have the "slickgrid-container" css class
// if it does then we won't create yet another grid, just stop there
- if (gridParentContainerElm.querySelectorAll('.slickgrid-container').length !== 0) {
+ if (!gridParentContainerElm || gridParentContainerElm.querySelectorAll('.slickgrid-container').length !== 0) {
return;
}
diff --git a/test/cypress/e2e/example25.cy.ts b/test/cypress/e2e/example25.cy.ts
new file mode 100644
index 000000000..26d0f0755
--- /dev/null
+++ b/test/cypress/e2e/example25.cy.ts
@@ -0,0 +1,282 @@
+import { addDay, format, isAfter, isBefore, isEqual } from '@formkit/tempo';
+
+const presetMinComplete = 5;
+const presetMaxComplete = 80;
+const presetMinDuration = 4;
+const presetMaxDuration = 88;
+const today = new Date();
+const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD');
+const presetHighestDay = format(addDay(new Date(), today.getDate() < 14 ? 30 : 25), 'YYYY-MM-DD');
+
+function isBetween(inputDate: Date | string, minDate: Date | string, maxDate: Date | string, isInclusive = false) {
+ let valid = false;
+ if (isInclusive) {
+ valid = isEqual(inputDate, minDate) || isEqual(inputDate, maxDate);
+ }
+ if (!valid) {
+ valid = isAfter(inputDate, minDate) && isBefore(inputDate, maxDate);
+ }
+ return valid;
+}
+
+function isSmallerOrEqual(inputDate: Date | string, maxDate: Date | string) {
+ return isBefore(inputDate, maxDate) || isEqual(inputDate, maxDate);
+}
+
+describe('Example 25 - Range Filters', () => {
+ it('should display Example title', () => {
+ cy.visit(`${Cypress.config('baseUrl')}/example25`);
+ cy.get('h3').should('contain', 'Example 25 - Range Filters');
+ });
+
+ it('should expect the grid to be sorted by "% Complete" descending and then by "Duration" ascending', () => {
+ cy.get('.grid25')
+ .get('.slick-header-column:nth(2)')
+ .find('.slick-sort-indicator-desc')
+ .should('have.length', 1)
+ .siblings('.slick-sort-indicator-numbered')
+ .contains('1');
+
+ cy.get('.grid25')
+ .get('.slick-header-column:nth(5)')
+ .find('.slick-sort-indicator-asc')
+ .should('have.length', 1)
+ .siblings('.slick-sort-indicator-numbered')
+ .contains('2');
+ });
+
+ it('should have "% Complete" fields within the range (inclusive) of the filters presets', () => {
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(2)')
+ .each(($cell) => {
+ const value = parseInt($cell.text().trim(), 10);
+ if (!isNaN(value)) {
+ expect(value >= presetMinComplete).to.eq(true);
+ expect(value <= presetMaxComplete).to.eq(true);
+ }
+ });
+ });
+ });
+
+ it('should have Finish Dates within the range (inclusive) of the filters presets', () => {
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(4)')
+ .each(($cell) => {
+ const isDateBetween = isBetween($cell.text(), presetLowestDay, presetHighestDay, true);
+ expect(isDateBetween).to.eq(true);
+ });
+ });
+ });
+
+ it('should have "Duration" fields within the range (exclusive by default) of the filters presets', () => {
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(5)')
+ .each(($cell) => {
+ const value = parseInt($cell.text().trim(), 10);
+ if (!isNaN(value)) {
+ expect(value >= presetMinDuration).to.eq(true);
+ expect(value <= presetMaxDuration).to.eq(true);
+ }
+ });
+ });
+ });
+
+ it('should change "% Complete" filter range by using the slider left handle (min value) to make it a higher min value and expect all rows to be within new range', () => {
+ let newLowest = presetMinComplete;
+ let newHighest = presetMaxComplete;
+ const allowedBuffer = 0.8;
+
+ // first input is the lowest range
+ cy.get('.slider-filter-input:nth(0)')
+ .as('range').invoke('val', 10).trigger('change', { force: true });
+
+ cy.get('.lowest-range-percentComplete')
+ .then(($lowest) => {
+ newLowest = parseInt($lowest.text(), 10);
+ });
+
+ cy.get('.highest-range-percentComplete')
+ .then(($highest) => {
+ newHighest = parseInt($highest.text(), 10);
+ });
+
+ cy.wait(5);
+
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row, idx) => {
+ if (idx > 6) {
+ return;
+ }
+ cy.wrap($row)
+ .children('.slick-cell:nth(2)')
+ .each(($cell) => {
+ const value = parseInt($cell.text().trim(), 10);
+ if (!isNaN(value) && $cell.text() !== '') {
+ expect(value >= (newLowest - allowedBuffer)).to.eq(true);
+ expect(value <= (newHighest + allowedBuffer)).to.eq(true);
+ }
+ });
+ });
+ });
+
+ it('should change the "Finish" date in the picker and expect all rows to be within new dates range', () => {
+ cy.get('.date-picker.search-filter.filter-finish')
+ .click();
+
+ cy.get('.vanilla-calendar-day_selected-first')
+ .should('exist');
+
+ cy.get('.vanilla-calendar-day_selected-intermediate')
+ .should('have.length.gte', 2);
+
+ cy.get('.vanilla-calendar-day_selected-last')
+ .should('exist');
+ });
+
+ it('should change the "Duration" input filter and expect all rows to be within new range', () => {
+ const newMin = 10;
+ const newMax = 40;
+
+ cy.get('[data-test=clear-filters]')
+ .click({ force: true });
+
+ cy.get('.search-filter.filter-duration')
+ .focus()
+ .type(`${newMin}..${newMax}`);
+
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row, idx) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(5)')
+ .each(($cell) => {
+ if (idx > 8) {
+ return;
+ }
+ const value = parseInt($cell.text().trim(), 10);
+ if (!isNaN(value)) {
+ expect(value >= newMin).to.eq(true);
+ expect(value <= newMax).to.eq(true);
+ }
+ });
+ });
+ });
+
+ describe('Set Dymamic Filters', () => {
+ const dynamicMinComplete = 15;
+ const dynamicMaxComplete = 85;
+ const dynamicMinDuration = 14;
+ const dynamicMaxDuration = 78;
+ const dynamicLowestDay = format(addDay(new Date(), -5), 'YYYY-MM-DD');
+ const dynamicHighestDay = format(addDay(new Date(), 25), 'YYYY-MM-DD');
+
+ it('should click on Set Dynamic Filters', () => {
+ cy.get('[data-test=set-dynamic-filter]')
+ .click();
+ });
+
+ it('should have "% Complete" fields within the exclusive range of the filters presets', () => {
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(2)')
+ .each(($cell) => {
+ const value = parseInt($cell.text().trim(), 10);
+ if (!isNaN(value)) {
+ expect(value >= dynamicMinComplete).to.eq(true);
+ expect(value <= dynamicMaxComplete).to.eq(true);
+ }
+ });
+ });
+ });
+
+ it('should have "Duration" fields within the inclusive range of the dynamic filters', () => {
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(5)')
+ .each(($cell) => {
+ const value = parseInt($cell.text().trim(), 10);
+ if (!isNaN(value)) {
+ expect(value >= dynamicMinDuration).to.eq(true);
+ expect(value <= dynamicMaxDuration).to.eq(true);
+ }
+ });
+ });
+ });
+
+ it('should have Start Dates smaller or equal to the dynamic filter', () => {
+ cy.get('.search-filter.filter-start')
+ .find('input')
+ .invoke('val')
+ .then(text => expect(text).to.eq(dynamicHighestDay));
+
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(3)')
+ .each(($cell) => {
+ const isDateBetween = isSmallerOrEqual($cell.text(), dynamicHighestDay);
+ expect(isDateBetween).to.eq(true);
+ });
+ });
+ });
+
+ it('should have Finish Dates within the range (inclusive) of the dynamic filters', () => {
+ cy.get('.search-filter.filter-finish')
+ .find('input')
+ .invoke('val')
+ .then(text => expect(text).to.eq(`${dynamicLowestDay} — ${dynamicHighestDay}`));
+
+ cy.get('.grid25')
+ .find('.slick-row')
+ .each(($row) => {
+ cy.wrap($row)
+ .children('.slick-cell:nth(4)')
+ .each(($cell) => {
+ const isDateBetween = isBetween($cell.text(), dynamicLowestDay, dynamicHighestDay, true);
+ expect(isDateBetween).to.eq(true);
+ });
+ });
+ });
+ });
+
+ describe('Set Dynamic Sorting', () => {
+ it('should click on "Clear Filters" then "Set Dynamic Sorting" buttons', () => {
+ cy.get('[data-test=clear-filters]')
+ .click();
+
+ cy.get('[data-test=set-dynamic-sorting]')
+ .click();
+ });
+
+ it('should expect the grid to be sorted by "Duration" ascending and "Start" descending', () => {
+ cy.get('.grid25')
+ .get('.slick-header-column:nth(2)')
+ .find('.slick-sort-indicator-asc')
+ .should('have.length', 1)
+ .siblings('.slick-sort-indicator-numbered')
+ .contains('2');
+
+ cy.get('.grid25')
+ .get('.slick-header-column:nth(4)')
+ .find('.slick-sort-indicator-desc')
+ .should('have.length', 1)
+ .siblings('.slick-sort-indicator-numbered')
+ .contains('1');
+ });
+ });
+});