Skip to content

Commit

Permalink
fix(filter): default operator of input filter should be empty
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiscoding-SE committed Nov 29, 2019
1 parent 5f2ec3f commit 17c905d
Show file tree
Hide file tree
Showing 16 changed files with 205 additions and 42 deletions.
5 changes: 4 additions & 1 deletion src/app/examples/grid-graphql.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {
gridStateSub: Subscription;

constructor(private translate: TranslateService) {
this.selectedLanguage = this.translate.getDefaultLang();
// always start with English for Cypress E2E tests to be consistent
const defaultLang = 'en';
this.translate.use(defaultLang);
this.selectedLanguage = defaultLang;
}

ngOnDestroy() {
Expand Down
14 changes: 7 additions & 7 deletions src/app/examples/grid-localization.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ <h2>{{title}}</h2>
<hr />

<div class="row col-sm-12">
<button class="btn btn-default btn-sm" (click)="switchLanguage()">
<button class="btn btn-default btn-sm" (click)="switchLanguage()" data-test="language-button">
<i class="fa fa-language"></i>
Switch Language
</button>
<b>Locale:</b> <span style="font-style: italic">{{selectedLanguage + '.json'}}</span>
<b>Locale:</b>
<span style="font-style: italic" data-test="selected-locale">
{{selectedLanguage + '.json'}}
</span>

<span style="margin-left: 20px">
<button class="btn btn-default btn-sm" (click)="exportToFile('csv')">
Expand All @@ -34,11 +37,8 @@ <h2>{{title}}</h2>
</div>

<div class="col-sm-12">
<angular-slickgrid gridId="grid12"
(onAngularGridCreated)="angularGridReady($event)"
[columnDefinitions]="columnDefinitions"
[gridOptions]="gridOptions"
[dataset]="dataset">
<angular-slickgrid gridId="grid12" (onAngularGridCreated)="angularGridReady($event)"
[columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions" [dataset]="dataset">
</angular-slickgrid>
</div>
</div>
9 changes: 7 additions & 2 deletions src/app/examples/grid-localization.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
GridOption
} from './../modules/angular-slickgrid';

const NB_ITEMS = 1500;

// create a custom translate Formatter (typically you would move that a separate file, for separation of concerns)
const taskTranslateFormatter: Formatter = (row: number, cell: number, value: any, columnDef: any, dataContext: any, grid: any) => {
const gridOptions = (grid && typeof grid.getOptions === 'function') ? grid.getOptions() : {};
Expand Down Expand Up @@ -60,7 +62,10 @@ export class GridLocalizationComponent implements OnInit {
duplicateTitleHeaderCount = 1;

constructor(private translate: TranslateService) {
this.selectedLanguage = this.translate.getDefaultLang();
// always start with English for Cypress E2E tests to be consistent
const defaultLang = 'en';
this.translate.use(defaultLang);
this.selectedLanguage = defaultLang;
}

ngOnInit(): void {
Expand Down Expand Up @@ -169,7 +174,7 @@ export class GridLocalizationComponent implements OnInit {
}
};

this.loadData(1000);
this.loadData(NB_ITEMS);
}

// mock a dataset
Expand Down
27 changes: 10 additions & 17 deletions src/app/examples/grid-state.component.html
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
<div class="container-fluid">
<h2>{{title}}</h2>
<div class="subtitle"
[innerHTML]="subTitle"></div>
<div class="subtitle" [innerHTML]="subTitle"></div>

<button class="btn btn-default btn-sm"
(click)="clearGridStateFromLocalStorage()"
data-test="reset-button">
<button class="btn btn-default btn-sm" (click)="clearGridStateFromLocalStorage()" data-test="reset-button">
<i class="fa fa-times"></i>
Clear Grid State from Local Storage &amp; Reset Grid
</button>
<button class="btn btn-default btn-sm"
(click)="switchLanguage()"
data-test="language-button">
<button class="btn btn-default btn-sm" (click)="switchLanguage()" data-test="language-button">
<i class="fa fa-language"></i>
Switch Language
</button>
<b>Locale:</b> <span style="font-style: italic"
data-test="selected-locale">{{selectedLanguage + '.json'}}</span>
<b>Locale:</b>
<span style="font-style: italic" data-test="selected-locale">
{{selectedLanguage + '.json'}}
</span>

<angular-slickgrid gridId="grid16"
[columnDefinitions]="columnDefinitions"
[gridOptions]="gridOptions"
[dataset]="dataset"
(onAngularGridCreated)="angularGridReady($event)"
(onGridStateChanged)="gridStateChanged($event)"
(onBeforeGridDestroy)="saveCurrentGridState($event)">
<angular-slickgrid gridId="grid16" [columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions"
[dataset]="dataset" (onAngularGridCreated)="angularGridReady($event)"
(onGridStateChanged)="gridStateChanged($event)" (onBeforeGridDestroy)="saveCurrentGridState($event)">
</angular-slickgrid>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ describe('InputFilter', () => {
const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-duration.filled');

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

it('should call "setValues" with extra spaces at the beginning of the searchTerms and trim value when "enableFilterTrimWhiteSpace" is enabled in grid options', () => {
it('should call "setValues" an operator and with with extra spaces at the beginning of the searchTerms and trim value when "enableFilterTrimWhiteSpace" is enabled in grid options', () => {
gridOptionMock.enableFilterTrimWhiteSpace = true;
const spyCallback = jest.spyOn(filterArguments, 'callback');

filter.init(filterArguments);
filter.setValues(' abc ');
filter.setValues(' abc ', 'EQ');
const filterElm = divContainer.querySelector<HTMLInputElement>('input.filter-duration');

filterElm.focus();
Expand All @@ -114,7 +114,7 @@ describe('InputFilter', () => {
const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-duration.filled');

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

it('should trigger the callback method when user types something in the input', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ describe('InputMaskFilter', () => {
filterElm.focus();
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['1234567890'], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: ['1234567890'], shouldTriggerQuery: true });
});

it('should call "setValues" with 10 digits and expect input value to be formatted as a phone as the mask format specifies', () => {
it('should call "setValues" an operator and with with 10 digits and expect input value to be formatted as a phone as the mask format specifies', () => {
mockColumn.filter.params = { mask: '(000) 000-0000' };
const spyCallback = jest.spyOn(filterArguments, 'callback');

filter.init(filterArguments);
filter.setValues('1234567890');
filter.setValues('1234567890', 'EQ');
const filterElm = divContainer.querySelector<HTMLInputElement>('input.filter-mask');
filterElm.focus();
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));
Expand All @@ -113,7 +113,7 @@ describe('InputMaskFilter', () => {
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(filterElm.value).toBe('(123) 456-7890');
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['1234567890'], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: ['1234567890'], shouldTriggerQuery: true });
});

it('should call "setValues" with 10 digits and expect it to work with using 9 instead of 0 in the mask', () => {
Expand All @@ -127,7 +127,7 @@ describe('InputMaskFilter', () => {
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(filterElm.value).toBe('(123) 456-7890');
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['1234567890'], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: ['1234567890'], shouldTriggerQuery: true });
});

it('should call "setValues" with a characters & numbers mask (e.g. postal code) and expect it to returned a formatted string', () => {
Expand All @@ -141,7 +141,7 @@ describe('InputMaskFilter', () => {
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(filterElm.value).toBe('H1H 1H1');
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['H1H1H1'], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: ['H1H1H1'], shouldTriggerQuery: true });
});

it('should call "setValues" with 10 digits and expect it to work even if input as extra spaces at the beginning when "enableFilterTrimWhiteSpace" is enabled in grid options', () => {
Expand All @@ -156,7 +156,7 @@ describe('InputMaskFilter', () => {
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(filterElm.value).toBe('(123) 456-7890');
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['1234567890'], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: ['1234567890'], shouldTriggerQuery: true });
});

it('should call "setValues" with 10 digits and expect it to work even if input as extra spaces at the beginning when "enableTrimWhiteSpace" is enabled in the column filter', () => {
Expand All @@ -172,7 +172,7 @@ describe('InputMaskFilter', () => {
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(filterElm.value).toBe('(123) 456-7890');
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['1234567890'], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: ['1234567890'], shouldTriggerQuery: true });
});

it('should call "setValues" all invalid characters and expect an empty shell as it does not match the mask', () => {
Expand All @@ -186,7 +186,7 @@ describe('InputMaskFilter', () => {
filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', { keyCode: 97, bubbles: true, cancelable: true }));

expect(filterElm.value).toBe('() -');
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: [''], shouldTriggerQuery: true });
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: '', searchTerms: [''], shouldTriggerQuery: true });
});

it('should trigger the callback method when user types something in the input', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ describe('SelectFilter', () => {
expect(filterListElm[1].checked).toBe(true);
expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'IN', searchTerms: ['female'], shouldTriggerQuery: true });
done();
});
}, 2);
});

it('should create the multi-select filter with a "collectionAsync" as an Observable and be able to call next on it', (done) => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/modules/angular-slickgrid/filters/inputFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class InputFilter implements Filter {

/** Getter to know what would be the default operator when none is specified */
get defaultOperator(): OperatorType | OperatorString {
return OperatorType.equal;
return OperatorType.empty;
}

/** Getter of input type (text, number, password) */
Expand Down
2 changes: 2 additions & 0 deletions test/cypress/integration/example1.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// <reference types="cypress" />

describe('Example 1 - Basic Grids', () => {
const titles = ['Title', 'Duration (days)', '% Complete', 'Start', 'Finish', 'Effort Driven'];

Expand Down
2 changes: 2 additions & 0 deletions test/cypress/integration/example10.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// <reference types="cypress" />

describe('Example 10 - Multiple Grids with Row Selection', () => {
const titles = ['', 'Title', 'Duration (days)', '% Complete', 'Start', 'Finish', 'Effort Driven'];

Expand Down
149 changes: 149 additions & 0 deletions test/cypress/integration/example12.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/// <reference types="cypress" />

describe('Example 12: Localization (i18n)', () => {
const fullEnglishTitles = ['Title', 'Description', 'Duration', 'Start', 'Finish', 'Completed', 'Completed'];
const fullFrenchTitles = ['Titre', 'Description', 'Durée', 'Début', 'Fin', 'Terminé', 'Terminé'];

beforeEach(() => {
cy.restoreLocalStorage();
});

afterEach(() => {
cy.saveLocalStorage();
});

it('should display Example title', () => {
cy.visit(`${Cypress.config('baseExampleUrl')}/localization`);
cy.get('h2').should('contain', 'Example 12: Localization (i18n)');
});

describe('English Locale', () => {
it('should have exact English Column Titles in the grid', () => {
cy.get('#grid12')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullEnglishTitles[index]));
});

it('should filter certain tasks with the word "ask 1" and expect filter to use contain/include text', () => {
const tasks = ['Task 1', 'Task 10', 'Task 11', 'Task 12'];

cy.get('.grid-canvas')
.find('.slick-row')
.should('be.visible');

cy.get('input.filter-title')
.type('ask 1');

cy.get('#grid12')
.find('.slick-row')
.each(($row, index) => {
if (index > tasks.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell')
.first()
.should('contain', tasks[index]);
});
});
});

describe('French locale', () => {
it('should reset filters and switch locale to French', () => {
cy.get('#grid12')
.find('button.slick-gridmenu-button')
.trigger('click')
.click();

cy.get(`.slick-gridmenu:visible`)
.find('.slick-gridmenu-item')
.first()
.find('span')
.contains('Clear All Filters')
.click();

cy.get('[data-test=language-button]')
.click();

cy.get('[data-test=selected-locale]')
.should('contain', 'fr.json');
});

it('should have French Column Titles in the grid after switching locale', () => {
cy.get('#grid12')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullFrenchTitles[index]));
});

it('should filter certain tasks', () => {
const tasks = ['Tâche 1', 'Tâche 10', 'Tâche 11', 'Tâche 12'];

cy.get('.grid-canvas')
.find('.slick-row')
.should('be.visible');

cy.get('input.filter-title')
.type('âche 1');

cy.get('#grid12')
.find('.slick-row')
.each(($row, index) => {
if (index > tasks.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell')
.first()
.should('contain', tasks[index]);
});
});

it('should reset filters before filtering duration', () => {
cy.get('#grid12')
.find('button.slick-gridmenu-button')
.trigger('click')
.click();

cy.get(`.slick-gridmenu:visible`)
.find('.slick-gridmenu-item')
.first()
.find('span')
.contains('Supprimer tous les filtres')
.click();
});

it('should filter duration with slider filter', () => {
cy.get('.filter-duration input[type=range]').as('range')
.invoke('val', 25)
.trigger('change');

cy.get('#grid12')
.find('.slick-row')
.each(($row, index) => {
let fullCellWidth;

// only checks first 5 rows
if (index > 5) {
return;
}

// get full cell width of the first cell, then return
cy.wrap($row).children('.slick-cell:nth(2)')
.first()
.then(($cell) => fullCellWidth = $cell.width());


cy.wrap($row)
.children('.slick-cell:nth(2)')
.children()
.should('have.css', 'background-color', 'rgb(255, 0, 0)')
.should(($el) => {
// calculate 25% and expect the element width to be about the calculated size with a (+/-)1px precision
const expectedWidth = (fullCellWidth * .25);
expect($el.width()).greaterThan(expectedWidth - 1);
expect($el.width()).lessThan(expectedWidth + 1);
});
});
});
});
});
2 changes: 2 additions & 0 deletions test/cypress/integration/example16.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// <reference types="cypress" />

describe('Example 16: Grid State & Presets using Local Storage', () => {
const fullEnglishTitles = ['', 'Title', 'Description', 'Duration', '% Complete', 'Start', 'Completed'];
const fullFrenchTitles = ['', 'Titre', 'Description', 'Durée', '% Achevée', 'Début', 'Terminé'];
Expand Down

0 comments on commit 17c905d

Please sign in to comment.