From 0de87ddf86b331b7d7199ea19c4cf61afd5e94bd Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Thu, 4 Mar 2021 18:08:32 -0500 Subject: [PATCH 1/4] fix(filters): string <> should be Not Contains instead of Not Equal - prefixing a text search with `<>` should be equivalent to "Not Contains" instead of "Not Equal", we can keep the `!=` as "Not Equal" so this way we have both available --- .../modules/angular-slickgrid/constants.ts | 1 + .../stringFilterCondition.ts | 2 + .../__tests__/compoundInputFilter.spec.ts | 90 ++++++++++--------- .../filters/compoundInputFilter.ts | 2 + .../models/locale.interface.ts | 3 + src/assets/i18n/en.json | 1 + src/assets/i18n/fr.json | 1 + 7 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/app/modules/angular-slickgrid/constants.ts b/src/app/modules/angular-slickgrid/constants.ts index e2c0b5804..db0d8803f 100644 --- a/src/app/modules/angular-slickgrid/constants.ts +++ b/src/app/modules/angular-slickgrid/constants.ts @@ -34,6 +34,7 @@ export class Constants { TEXT_LAST_UPDATE: 'Last Update', TEXT_LESS_THAN: 'Less than', TEXT_LESS_THAN_OR_EQUAL_TO: 'Less than or equal to', + TEXT_NOT_CONTAINS: 'Not contains', TEXT_NOT_EQUAL_TO: 'Not equal to', TEXT_PAGE: 'Page', TEXT_REFRESH_DATASET: 'Refresh Dataset', diff --git a/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts index 6d1f46c04..286c486f5 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts @@ -22,6 +22,8 @@ export const executeStringFilterCondition: FilterCondition = ((options: FilterCo return cellValue.startsWith(parsedSearchValue); } else if (options.operator === '' || options.operator === OperatorType.contains) { return (cellValue.indexOf(parsedSearchValue) > -1); + } else if (options.operator === '<>' || options.operator === OperatorType.notContains) { + return (cellValue.indexOf(parsedSearchValue) === -1); } return testFilterCondition(options.operator || '==', cellValue, parsedSearchValue); }) as FilterCondition; diff --git a/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts b/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts index a972689b2..b6757dec8 100644 --- a/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts +++ b/src/app/modules/angular-slickgrid/filters/__tests__/compoundInputFilter.spec.ts @@ -29,7 +29,7 @@ describe('CompoundInputFilter', () => { let divContainer: HTMLDivElement; let filter: CompoundInputFilter; let filterArguments: FilterArguments; - let spyGetHeaderRow; + let spyGetHeaderRow: jest.SpyInstance; let mockColumn: Column; let translate: TranslateService; @@ -62,6 +62,7 @@ describe('CompoundInputFilter', () => { LESS_THAN_OR_EQUAL_TO: 'Less than or equal to', GREATER_THAN: 'Greater than', GREATER_THAN_OR_EQUAL_TO: 'Greater than or equal to', + NOT_CONTAINS: 'Not contains', NOT_EQUAL_TO: 'Not equal to', }); translate.setTranslation('fr', { @@ -74,6 +75,7 @@ describe('CompoundInputFilter', () => { LESS_THAN_OR_EQUAL_TO: 'Plus petit ou égal à', GREATER_THAN: 'Plus grand que', GREATER_THAN_OR_EQUAL_TO: 'Plus grand ou égal à', + NOT_CONTAINS: 'Ne contient pas', NOT_EQUAL_TO: 'Non égal à', }); translate.setDefaultLang('en'); @@ -87,7 +89,7 @@ describe('CompoundInputFilter', () => { }); it('should throw an error when trying to call init without any arguments', () => { - expect(() => filter.init(null)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.'); + expect(() => filter.init(null as any)).toThrowError('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.'); }); it('should initialize the filter', () => { @@ -101,10 +103,10 @@ describe('CompoundInputFilter', () => { it('should have a placeholder when defined in its column definition', () => { const testValue = 'test placeholder'; - mockColumn.filter.placeholder = testValue; + mockColumn.filter!.placeholder = testValue; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; expect(filterInputElm.placeholder).toBe(testValue); }); @@ -114,7 +116,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.setValues(['abc']); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.dispatchEvent(new (window.window as any).Event('input', { keyCode: 97, bubbles: true, cancelable: true })); @@ -129,7 +131,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.setValues(['abc']); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); const event = new (window.window as any).Event('keyup', { bubbles: true, cancelable: true }); @@ -146,7 +148,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.setValues(['abc']); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); const event = new (window.window as any).Event('keyup', { bubbles: true, cancelable: true }); @@ -165,7 +167,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArgs); filter.setValues(['9']); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.dispatchEvent(new (window.window as any).Event('input', { keyCode: 97, bubbles: true, cancelable: true })); @@ -180,7 +182,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.setValues(['9'], OperatorType.greaterThanOrEqual); - const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select'); + const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select') as HTMLInputElement; filterOperatorElm.dispatchEvent(new Event('change')); @@ -194,7 +196,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.setValues(['9']); - const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select'); + const filterOperatorElm = divContainer.querySelector('.search-filter.filter-duration select') as HTMLInputElement; filterOperatorElm.value = '<='; filterOperatorElm.dispatchEvent(new Event('change')); @@ -210,7 +212,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArgs); filter.setValues([' 987 ']); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.dispatchEvent(new (window.window as any).Event('input', { keyCode: 97, bubbles: true, cancelable: true })); @@ -220,14 +222,14 @@ describe('CompoundInputFilter', () => { it('should call "setValues" with extra spaces at the beginning of the searchTerms and trim value when "enableTrimWhiteSpace" is enabled in the column filter', () => { gridOptionMock.enableFilterTrimWhiteSpace = false; - mockColumn.filter.enableTrimWhiteSpace = true; + mockColumn.filter!.enableTrimWhiteSpace = true; mockColumn.type = FieldType.number; const filterArgs = { ...filterArguments, operator: '>' } as FilterArguments; const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArgs); filter.setValues([' 987 ']); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.dispatchEvent(new (window.window as any).Event('input', { keyCode: 97, bubbles: true, cancelable: true })); @@ -239,7 +241,7 @@ describe('CompoundInputFilter', () => { const spyCallback = jest.spyOn(filterArguments, 'callback'); filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; filterInputElm.focus(); filterInputElm.value = 'a'; @@ -252,7 +254,7 @@ describe('CompoundInputFilter', () => { filterArguments.searchTerms = ['xyz']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; expect(filterInputElm.value).toBe('xyz'); }); @@ -261,7 +263,7 @@ describe('CompoundInputFilter', () => { filterArguments.searchTerms = ['']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.search-filter.filter-duration.filled'); expect(filterInputElm.value).toBe(''); @@ -273,16 +275,16 @@ describe('CompoundInputFilter', () => { filterArguments.searchTerms = ['9']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); expect(filterInputElm.value).toBe('9'); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('< Less than'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('<= Less than or equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][4].textContent)).toBe('> Greater than'); - expect(removeExtraSpaces(filterOperatorElm[0][5].textContent)).toBe('>= Greater than or equal to'); - expect(removeExtraSpaces(filterOperatorElm[0][6].textContent)).toBe('<> Not equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('<= Less than or equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('> Greater than'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('>= Greater than or equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Not equal to'); }); it('should create the input filter with operator dropdown options related to strings when column definition type is FieldType.string', () => { @@ -290,14 +292,16 @@ describe('CompoundInputFilter', () => { filterArguments.searchTerms = ['xyz']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); expect(filterInputElm.value).toBe('xyz'); - expect(removeExtraSpaces(filterOperatorElm[0][0].textContent)).toBe(' Contains'); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Equals'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('a* Starts With'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('*z Ends With'); + expect(removeExtraSpaces(filterOperatorElm[0][0].textContent!)).toBe(' Contains'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('<> Not contains'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('= Equals'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('!= Not equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('a* Starts With'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('*z Ends With'); }); it('should trigger a callback with the clear filter set when calling the "clear" method', () => { @@ -306,7 +310,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.clear(); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.search-filter.filter-duration.filled'); @@ -321,7 +325,7 @@ describe('CompoundInputFilter', () => { filter.init(filterArguments); filter.clear(false); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterFilledElms = divContainer.querySelectorAll('.search-filter.filter-duration.filled'); @@ -341,16 +345,16 @@ describe('CompoundInputFilter', () => { filterArguments.searchTerms = ['9']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); expect(filterInputElm.value).toBe('9'); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('< Plus petit que'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('<= Plus petit ou égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][4].textContent)).toBe('> Plus grand que'); - expect(removeExtraSpaces(filterOperatorElm[0][5].textContent)).toBe('>= Plus grand ou égal à'); - expect(removeExtraSpaces(filterOperatorElm[0][6].textContent)).toBe('<> Non égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Plus petit que'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('<= Plus petit ou égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('> Plus grand que'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('>= Plus grand ou égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Non égal à'); }); it('should have French text translated with operator dropdown options related to strings when column definition type is FieldType.string', () => { @@ -358,14 +362,16 @@ describe('CompoundInputFilter', () => { filterArguments.searchTerms = ['xyz']; filter.init(filterArguments); - const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input'); + const filterInputElm = divContainer.querySelector('.search-filter.filter-duration input') as HTMLInputElement; const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); expect(filterInputElm.value).toBe('xyz'); - expect(removeExtraSpaces(filterOperatorElm[0][0].textContent)).toBe(' Contient'); - expect(removeExtraSpaces(filterOperatorElm[0][1].textContent)).toBe('= Égale'); - expect(removeExtraSpaces(filterOperatorElm[0][2].textContent)).toBe('a* Commence par'); - expect(removeExtraSpaces(filterOperatorElm[0][3].textContent)).toBe('*z Se termine par'); + expect(removeExtraSpaces(filterOperatorElm[0][0].textContent!)).toBe(' Contient'); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('<> Ne contient pas'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('= Égale'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('!= Non égal à'); + expect(removeExtraSpaces(filterOperatorElm[0][4].textContent!)).toBe('a* Commence par'); + expect(removeExtraSpaces(filterOperatorElm[0][5].textContent!)).toBe('*z Se termine par'); }); }); }); diff --git a/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts b/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts index 577ad7b1c..138e82538 100644 --- a/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts +++ b/src/app/modules/angular-slickgrid/filters/compoundInputFilter.ts @@ -166,7 +166,9 @@ export class CompoundInputFilter implements Filter { case FieldType.password: optionValues = [ { operator: '' as OperatorString, description: this.getOutputText('CONTAINS', 'TEXT_CONTAINS', 'Contains') }, + { operator: '<>' as OperatorString, description: this.getOutputText('NOT_CONTAINS', 'TEXT_NOT_CONTAINS', 'Not Contains') }, { operator: '=' as OperatorString, description: this.getOutputText('EQUALS', 'TEXT_EQUALS', 'Equals') }, + { operator: '!=' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') }, { operator: 'a*' as OperatorString, description: this.getOutputText('STARTS_WITH', 'TEXT_STARTS_WITH', 'Starts with') }, { operator: '*z' as OperatorString, description: this.getOutputText('ENDS_WITH', 'TEXT_ENDS_WITH', 'Ends with') }, ]; diff --git a/src/app/modules/angular-slickgrid/models/locale.interface.ts b/src/app/modules/angular-slickgrid/models/locale.interface.ts index ddcca81b1..be289d3db 100644 --- a/src/app/modules/angular-slickgrid/models/locale.interface.ts +++ b/src/app/modules/angular-slickgrid/models/locale.interface.ts @@ -89,6 +89,9 @@ export interface Locale { /** Text "Less than or equal to" shown in Compound Editors/Filters as an Operator */ TEXT_LESS_THAN_OR_EQUAL_TO: string; + /** Text "Not contains" shown in Compound Editors/Filters as an Operator */ + TEXT_NOT_CONTAINS: string; + /** Text "Not equal to" shown in Compound Editors/Filters as an Operator */ TEXT_NOT_EQUAL_TO: string; diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 5482aa132..d20391890 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -33,6 +33,7 @@ "LAST_UPDATE": "Last Update", "LESS_THAN": "Less than", "LESS_THAN_OR_EQUAL_TO": "Less than or equal to", + "NOT_CONTAINS": "Not contains", "NOT_EQUAL_TO": "Not equal to", "NOT_IN_COLLECTION_SEPERATED_BY_COMMA": "Search items not in a collection, must be separated by a comma (a,b)", "OF": "of", diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 017e8f2fe..4cc76e998 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -33,6 +33,7 @@ "LAST_UPDATE": "Dernière mise à jour", "LESS_THAN": "Plus petit que", "LESS_THAN_OR_EQUAL_TO": "Plus petit ou égal à", + "NOT_CONTAINS": "Ne contient pas", "NOT_EQUAL_TO": "Non égal à", "NOT_IN_COLLECTION_SEPERATED_BY_COMMA": "Recherche excluant certain éléments d'une collection, doit être séparé par une virgule (a,b)", "OF": "de", From ce790390c5ce388e176af2d15b3f0903ce34c2ba Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Thu, 4 Mar 2021 19:25:57 -0500 Subject: [PATCH 2/4] tests: add missing unit tests --- .../__tests__/stringFilterCondition.spec.ts | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts index 3e672fe34..387245fb8 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts @@ -1,17 +1,17 @@ -import { FieldType, FilterConditionOption, OperatorType } from '../../models/index'; +import { FieldType, FilterConditionOption, OperatorType, SearchTerm } from '../../models/index'; import { executeFilterConditionTest } from '../filterConditionProcesses'; import { executeStringFilterCondition, getFilterParsedText } from '../stringFilterCondition'; describe('executeStringFilterCondition method', () => { it('should return True when no cell input value is provided which is equal to the default search term, neither search terms', () => { - const searchTerms = []; + const searchTerms: SearchTerm[] = []; const options = { dataKey: '', operator: 'EQ', cellValue: '', fieldType: FieldType.string } as FilterConditionOption; const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when cell input value is null and is equal to the default search term, neither search terms', () => { - const searchTerms = []; + const searchTerms: SearchTerm[] = []; const options = { dataKey: '', operator: 'EQ', cellValue: null, fieldType: FieldType.string } as FilterConditionOption; const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); @@ -25,7 +25,7 @@ describe('executeStringFilterCondition method', () => { }); it('should return False when any cell input value is provided without any search terms', () => { - const searchTerms = []; + const searchTerms: SearchTerm[] = []; const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string } as FilterConditionOption; const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(false); @@ -60,7 +60,7 @@ describe('executeStringFilterCondition method', () => { }); it('should return False when the cell value is equal to at least 1 of the searchTerms', () => { - const searchTerms = []; + const searchTerms: SearchTerm[] = []; const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['bar', 'foo', 'John'] } as FilterConditionOption; const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(false); @@ -94,6 +94,20 @@ describe('executeStringFilterCondition method', () => { expect(output).toBe(true); }); + it('should return False when search term is a substring of the cell value and the operator is "<>" (not contains)', () => { + const searchTerms = ['bost']; + const options = { dataKey: '', operator: '<>', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); + expect(output).toBe(false); + }); + + it('should return True when search term is a substring of the cell value and the operator is "!=" (not contains) because "!=" compares agains the entire string', () => { + const searchTerms = ['bost']; + const options = { dataKey: '', operator: '!=', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); + expect(output).toBe(true); + }); + it('should return True when input value provided starts with same substring and the operator is empty string', () => { const searchTerms = ['abb']; const options = { dataKey: '', operator: '', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; From 11ca2723335274440ccbdf7a0857c5805644cc66 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 5 Mar 2021 07:05:54 -0500 Subject: [PATCH 3/4] tests: try to fix Cypress flaky test --- test/cypress/integration/example17.spec.js | 4 +--- test/cypress/package.json | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/cypress/integration/example17.spec.js b/test/cypress/integration/example17.spec.js index acebaf077..ac986784c 100644 --- a/test/cypress/integration/example17.spec.js +++ b/test/cypress/integration/example17.spec.js @@ -16,7 +16,7 @@ describe('Example 17 - Row Move & Checkbox Selector Selector Plugins', () => { .each(($child, index) => expect($child.text()).to.eq(fullTitles[index])); }); - it('should drag opened Row Detail to another position in the grid', () => { + it('should drag opened Row Detail to another position in the grid & expect row to be moved to another row index', () => { cy.get('[style="top:35px"] > .slick-cell.cell-reorder').as('moveIconTask1'); cy.get('[style="top:105px"] > .slick-cell.cell-reorder').as('moveIconTask3'); @@ -32,9 +32,7 @@ describe('Example 17 - Row Move & Checkbox Selector Selector Plugins', () => { cy.get('input[type="checkbox"]:checked') .should('have.length', 0); - }); - it('should expect row to be moved to another row index', () => { cy.get('.slick-viewport-top.slick-viewport-left') .scrollTo('top'); diff --git a/test/cypress/package.json b/test/cypress/package.json index e77c6c558..c725e3399 100644 --- a/test/cypress/package.json +++ b/test/cypress/package.json @@ -10,8 +10,8 @@ "author": "Ghislain B.", "license": "MIT", "devDependencies": { - "cypress": "^6.5.0", + "cypress": "^6.6.0", "mocha": "^8.3.0", - "mochawesome": "^6.2.1" + "mochawesome": "^6.2.2" } -} +} \ No newline at end of file From 2d0388ecaaa34f7fea2aae8d125c7e0f979d5073 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 5 Mar 2021 07:18:07 -0500 Subject: [PATCH 4/4] tests: keep jquery 3.5.1 to fix failing Cypress test --- package.json | 4 ++-- test/cypress/integration/example17.spec.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 69040f73f..01a2011bf 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "excel-builder-webpacker": "^1.0.6", "flatpickr": "^4.6.9", "font-awesome": "^4.7.0", - "jquery": "^3.5.1", + "jquery": "~3.5.1", "jquery-ui-dist": "^1.12.1", "moment-mini": "^2.24.0", "rxjs": "^6.3.3", @@ -177,4 +177,4 @@ "yargs": "^16.2.0", "zone.js": "~0.9.1" } -} +} \ No newline at end of file diff --git a/test/cypress/integration/example17.spec.js b/test/cypress/integration/example17.spec.js index ac986784c..acebaf077 100644 --- a/test/cypress/integration/example17.spec.js +++ b/test/cypress/integration/example17.spec.js @@ -16,7 +16,7 @@ describe('Example 17 - Row Move & Checkbox Selector Selector Plugins', () => { .each(($child, index) => expect($child.text()).to.eq(fullTitles[index])); }); - it('should drag opened Row Detail to another position in the grid & expect row to be moved to another row index', () => { + it('should drag opened Row Detail to another position in the grid', () => { cy.get('[style="top:35px"] > .slick-cell.cell-reorder').as('moveIconTask1'); cy.get('[style="top:105px"] > .slick-cell.cell-reorder').as('moveIconTask3'); @@ -32,7 +32,9 @@ describe('Example 17 - Row Move & Checkbox Selector Selector Plugins', () => { cy.get('input[type="checkbox"]:checked') .should('have.length', 0); + }); + it('should expect row to be moved to another row index', () => { cy.get('.slick-viewport-top.slick-viewport-left') .scrollTo('top');