diff --git a/webapp/src/blocks/filterGroup.ts b/webapp/src/blocks/filterGroup.ts index ee2e498d2..d6048aecc 100644 --- a/webapp/src/blocks/filterGroup.ts +++ b/webapp/src/blocks/filterGroup.ts @@ -11,7 +11,7 @@ type FilterGroup = { } function isAFilterGroupInstance(object: (FilterClause | FilterGroup)): object is FilterGroup { - return 'innerOperation' in object && 'filters' in object + return 'operation' in object && 'filters' in object } function createFilterGroup(o?: FilterGroup): FilterGroup { diff --git a/webapp/src/cardFilter.test.ts b/webapp/src/cardFilter.test.ts new file mode 100644 index 000000000..66a66445b --- /dev/null +++ b/webapp/src/cardFilter.test.ts @@ -0,0 +1,338 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import {mocked} from 'ts-jest/utils' + +import {createFilterClause} from './blocks/filterClause' + +import {createFilterGroup} from './blocks/filterGroup' +import {CardFilter} from './cardFilter' +import {TestBlockFactory} from './test/testBlockFactory' +import {Utils} from './utils' +import {IPropertyTemplate} from './blocks/board' + +jest.mock('./utils') +const mockedUtils = mocked(Utils, true) +describe('src/cardFilter', () => { + const board = TestBlockFactory.createBoard() + board.id = '1' + board.rootId = '1' + const card1 = TestBlockFactory.createCard(board) + card1.id = '1' + card1.title = 'card1' + card1.fields.properties.propertyId = 'Status' + const filterClause = createFilterClause({propertyId: 'propertyId', condition: 'isNotEmpty', values: ['Status']}) + describe('verify isClauseMet method', () => { + test('should be true with isNotEmpty clause', () => { + const filterClauseIsNotEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isNotEmpty', values: ['Status']}) + const result = CardFilter.isClauseMet(filterClauseIsNotEmpty, [], card1) + expect(result).toBeTruthy() + }) + test('should be false with isEmpty clause', () => { + const filterClauseIsEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isEmpty', values: ['Status']}) + const result = CardFilter.isClauseMet(filterClauseIsEmpty, [], card1) + expect(result).toBeFalsy() + }) + test('should be true with includes clause', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const result = CardFilter.isClauseMet(filterClauseIncludes, [], card1) + expect(result).toBeTruthy() + }) + test('should be true with includes and no values clauses', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: []}) + const result = CardFilter.isClauseMet(filterClauseIncludes, [], card1) + expect(result).toBeTruthy() + }) + test('should be false with notIncludes clause', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const result = CardFilter.isClauseMet(filterClauseNotIncludes, [], card1) + expect(result).toBeFalsy() + }) + test('should be true with notIncludes and no values clauses', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: []}) + const result = CardFilter.isClauseMet(filterClauseNotIncludes, [], card1) + expect(result).toBeTruthy() + }) + }) + describe('verify isFilterGroupMet method', () => { + test('should return true with no filter', () => { + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [], + }) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeTruthy() + }) + test('should return true with or operation and 2 filterCause, one is false ', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'or', + filters: [ + filterClauseNotIncludes, + filterClause, + ], + }) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeTruthy() + }) + test('should return true with or operation and 2 filterCause, 1 filtergroup in filtergroup, one filterClause is false ', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const filterGroupInFilterGroup = createFilterGroup({ + operation: 'or', + filters: [ + filterClauseNotIncludes, + filterClause, + ], + }) + const filterGroup = createFilterGroup({ + operation: 'or', + filters: [], + }) + filterGroup.filters.push(filterGroupInFilterGroup) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeTruthy() + }) + test('should return false with or operation and two filterCause, two are false ', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const filterClauseEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isEmpty', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'or', + filters: [ + filterClauseNotIncludes, + filterClauseEmpty, + ], + }) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeFalsy() + }) + test('should return false with and operation and 2 filterCause, one is false ', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [ + filterClauseNotIncludes, + filterClause, + ], + }) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeFalsy() + }) + test('should return true with and operation and 2 filterCause, two are true ', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [ + filterClauseIncludes, + filterClause, + ], + }) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeTruthy() + }) + test('should return true with or operation and 2 filterCause, 1 filtergroup in filtergroup, one filterClause is false ', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const filterGroupInFilterGroup = createFilterGroup({ + operation: 'and', + filters: [ + filterClauseNotIncludes, + filterClause, + ], + }) + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [], + }) + filterGroup.filters.push(filterGroupInFilterGroup) + const result = CardFilter.isFilterGroupMet(filterGroup, [], card1) + expect(result).toBeFalsy() + }) + }) + describe('verify propertyThatMeetsFilterClause method', () => { + test('should return Utils.assertFailure and filterClause propertyId ', () => { + const filterClauseIsNotEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isNotEmpty', values: ['Status']}) + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIsNotEmpty, []) + expect(mockedUtils.assertFailure).toBeCalledTimes(1) + expect(result.id).toEqual(filterClauseIsNotEmpty.propertyId) + }) + test('should return filterClause propertyId with non-select template and isNotEmpty clause ', () => { + const filterClauseIsNotEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isNotEmpty', values: ['Status']}) + const templateFilter: IPropertyTemplate = { + id: filterClauseIsNotEmpty.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIsNotEmpty, [templateFilter]) + expect(result.id).toEqual(filterClauseIsNotEmpty.propertyId) + expect(result.value).toBeFalsy() + }) + test('should return filterClause propertyId with select template , an option and isNotEmpty clause ', () => { + const filterClauseIsNotEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isNotEmpty', values: ['Status']}) + const templateFilter: IPropertyTemplate = { + id: filterClauseIsNotEmpty.propertyId, + name: 'template', + type: 'select', + options: [{ + id: 'idOption', + value: '', + color: '', + }], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIsNotEmpty, [templateFilter]) + expect(result.id).toEqual(filterClauseIsNotEmpty.propertyId) + expect(result.value).toEqual('idOption') + }) + test('should return filterClause propertyId with select template , no option and isNotEmpty clause ', () => { + const filterClauseIsNotEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isNotEmpty', values: ['Status']}) + const templateFilter: IPropertyTemplate = { + id: filterClauseIsNotEmpty.propertyId, + name: 'template', + type: 'select', + options: [], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIsNotEmpty, [templateFilter]) + expect(result.id).toEqual(filterClauseIsNotEmpty.propertyId) + expect(result.value).toBeFalsy() + }) + + test('should return filterClause propertyId with template, and includes clause with values', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const templateFilter: IPropertyTemplate = { + id: filterClauseIncludes.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIncludes, [templateFilter]) + expect(result.id).toEqual(filterClauseIncludes.propertyId) + expect(result.value).toEqual(filterClauseIncludes.values[0]) + }) + test('should return filterClause propertyId with template, and includes clause with no values', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: []}) + const templateFilter: IPropertyTemplate = { + id: filterClauseIncludes.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIncludes, [templateFilter]) + expect(result.id).toEqual(filterClauseIncludes.propertyId) + expect(result.value).toBeFalsy() + }) + test('should return filterClause propertyId with template, and notIncludes clause', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: []}) + const templateFilter: IPropertyTemplate = { + id: filterClauseNotIncludes.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseNotIncludes, [templateFilter]) + expect(result.id).toEqual(filterClauseNotIncludes.propertyId) + expect(result.value).toBeFalsy() + }) + test('should return filterClause propertyId with template, and isEmpty clause', () => { + const filterClauseIsEmpty = createFilterClause({propertyId: 'propertyId', condition: 'isEmpty', values: []}) + const templateFilter: IPropertyTemplate = { + id: filterClauseIsEmpty.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertyThatMeetsFilterClause(filterClauseIsEmpty, [templateFilter]) + expect(result.id).toEqual(filterClauseIsEmpty.propertyId) + expect(result.value).toBeFalsy() + }) + }) + describe('verify propertiesThatMeetFilterGroup method', () => { + test('should return {} with undefined filterGroup', () => { + const result = CardFilter.propertiesThatMeetFilterGroup(undefined, []) + expect(result).toEqual({}) + }) + test('should return {} with filterGroup without filter', () => { + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [], + }) + const result = CardFilter.propertiesThatMeetFilterGroup(filterGroup, []) + expect(result).toEqual({}) + }) + test('should return {} with filterGroup, or operation and no template', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'or', + filters: [ + filterClauseIncludes, + filterClause, + ], + }) + const result = CardFilter.propertiesThatMeetFilterGroup(filterGroup, []) + expect(result).toEqual({}) + }) + test('should return a result with filterGroup, or operation and template', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'or', + filters: [ + filterClauseIncludes, + filterClause, + ], + }) + const templateFilter: IPropertyTemplate = { + id: filterClauseIncludes.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertiesThatMeetFilterGroup(filterGroup, [templateFilter]) + expect(result).toBeDefined() + expect(result.propertyId).toEqual(filterClauseIncludes.values[0]) + }) + test('should return {} with filterGroup, and operation and no template', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [ + filterClauseIncludes, + filterClause, + ], + }) + const result = CardFilter.propertiesThatMeetFilterGroup(filterGroup, []) + expect(result).toEqual({}) + }) + + test('should return a result with filterGroup, and operation and template', () => { + const filterClauseIncludes = createFilterClause({propertyId: 'propertyId', condition: 'includes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'and', + filters: [ + filterClauseIncludes, + filterClause, + ], + }) + const templateFilter: IPropertyTemplate = { + id: filterClauseIncludes.propertyId, + name: 'template', + type: 'text', + options: [], + } + const result = CardFilter.propertiesThatMeetFilterGroup(filterGroup, [templateFilter]) + expect(result).toBeDefined() + expect(result.propertyId).toEqual(filterClauseIncludes.values[0]) + }) + }) + describe('verify applyFilterGroup method', () => { + test('should return array with card1', () => { + const filterClauseNotIncludes = createFilterClause({propertyId: 'propertyId', condition: 'notIncludes', values: ['Status']}) + const filterGroup = createFilterGroup({ + operation: 'or', + filters: [ + filterClauseNotIncludes, + filterClause, + ], + }) + const result = CardFilter.applyFilterGroup(filterGroup, [], [card1]) + expect(result).toBeDefined() + expect(result[0]).toEqual(card1) + }) + }) +})