From 03b5c40e8a658137019da873f2d190473e788fbc Mon Sep 17 00:00:00 2001 From: gitstart-twenty <140154534+gitstart-twenty@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:08:01 +0100 Subject: [PATCH] Add tests for `modules/object-record/object-filter-dropdown` (#3399) * Add tests for `modules/object-record/object-filter-dropdown` Co-authored-by: KlingerMatheus * Fix linter Co-authored-by: v1b3m Co-authored-by: KlingerMatheus * Revert unwanted changes Co-authored-by: v1b3m Co-authored-by: KlingerMatheus --------- Co-authored-by: gitstart-twenty Co-authored-by: KlingerMatheus Co-authored-by: v1b3m --- .../__tests__/useFilterDropdown.test.tsx | 285 ++++++++++++++++++ .../utils/__tests__/getOperandLabel.test.tsx | 48 +++ .../getOperandsForFilterType.test.tsx | 30 ++ 3 files changed, 363 insertions(+) create mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx create mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.tsx create mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx new file mode 100644 index 000000000..f47592352 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx @@ -0,0 +1,285 @@ +import { expect } from '@storybook/test'; +import { act, renderHook, waitFor } from '@testing-library/react'; +import { RecoilRoot } from 'recoil'; + +import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; +import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; +import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; + +const filterDropdownId = 'filterDropdownId'; +const renderHookConfig = { + wrapper: RecoilRoot, +}; + +const filterDefinitions: FilterDefinition[] = [ + { + fieldMetadataId: 'id', + label: 'definition label', + iconName: 'icon', + type: 'TEXT', + }, +]; + +const mockFilter: Filter = { + definition: filterDefinitions[0], + displayValue: '', + fieldMetadataId: '', + operand: ViewFilterOperand.Is, + value: '', +}; + +describe('useFilterDropdown', () => { + it('should set availableFilterDefinitions', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.availableFilterDefinitions).toEqual([]); + + act(() => { + result.current.setAvailableFilterDefinitions(filterDefinitions); + }); + + await waitFor(() => { + expect(result.current.availableFilterDefinitions).toEqual( + filterDefinitions, + ); + }); + }); + + it('should set onFilterSelect', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.onFilterSelect).toBeUndefined(); + + act(() => { + result.current.setOnFilterSelect( + (_currVal?: Filter) => (_filter: Filter) => {}, + ); + }); + await waitFor(() => { + expect(typeof result.current.onFilterSelect).toBe('function'); + }); + }); + + it('should set selectedOperandInDropdown', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + const mockOperand = ViewFilterOperand.Contains; + + expect(result.current.selectedOperandInDropdown).toBeNull(); + + act(() => { + result.current.setSelectedOperandInDropdown(mockOperand); + }); + + expect(result.current.selectedOperandInDropdown).toBe(mockOperand); + }); + + it('should set selectedFilter', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.selectedFilter).toBeUndefined(); + + act(() => { + result.current.setSelectedFilter(mockFilter); + }); + + await waitFor(() => { + expect(result.current.selectedFilter).toBe(mockFilter); + }); + }); + + it('should set filterDefinitionUsedInDropdown', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.filterDefinitionUsedInDropdown).toBeNull(); + + act(() => { + result.current.setFilterDefinitionUsedInDropdown(filterDefinitions[0]); + }); + + await waitFor(() => { + expect(result.current.filterDefinitionUsedInDropdown).toBe( + filterDefinitions[0], + ); + }); + }); + + it('should set objectFilterDropdownSearchInput', async () => { + const mockResult = 'value'; + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.objectFilterDropdownSearchInput).toBe(''); + + act(() => { + result.current.setObjectFilterDropdownSearchInput(mockResult); + }); + + await waitFor(() => { + expect(result.current.objectFilterDropdownSearchInput).toBe(mockResult); + }); + }); + + it('should set objectFilterDropdownSelectedEntityId', async () => { + const mockResult = 'value'; + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.objectFilterDropdownSelectedEntityId).toBeNull(); + + act(() => { + result.current.setObjectFilterDropdownSelectedEntityId(mockResult); + }); + + await waitFor(() => { + expect(result.current.objectFilterDropdownSelectedEntityId).toBe( + mockResult, + ); + }); + }); + + it('should set objectFilterDropdownSelectedRecordIds', async () => { + const mockResult = ['id-0', 'id-1', 'id-2']; + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.objectFilterDropdownSelectedRecordIds).toHaveLength( + 0, + ); + + act(() => { + result.current.setObjectFilterDropdownSelectedRecordIds(mockResult); + }); + + await waitFor(() => { + expect( + result.current.objectFilterDropdownSelectedRecordIds, + ).toStrictEqual(mockResult); + }); + }); + + it('should set isObjectFilterDropdownOperandSelectUnfolded', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.isObjectFilterDropdownOperandSelectUnfolded).toBe( + false, + ); + + act(() => { + result.current.setIsObjectFilterDropdownOperandSelectUnfolded(true); + }); + + await waitFor(() => { + expect(result.current.isObjectFilterDropdownOperandSelectUnfolded).toBe( + true, + ); + }); + }); + + it('should set isObjectFilterDropdownUnfolded', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.isObjectFilterDropdownUnfolded).toBe(false); + + act(() => { + result.current.setIsObjectFilterDropdownUnfolded(true); + }); + + await waitFor(() => { + expect(result.current.isObjectFilterDropdownUnfolded).toBe(true); + }); + }); + + it('should reset filter', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + act(() => { + result.current.selectFilter(mockFilter); + }); + + await waitFor(() => { + expect(result.current.selectedFilter).toStrictEqual(mockFilter); + }); + + act(() => { + result.current.resetFilter(); + }); + + await waitFor(() => { + expect(result.current.selectedFilter).toBeUndefined(); + }); + }); + + it('should call onFilterSelect when a filter option is set', async () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + const onFilterSelectMock = jest.fn(); + + expect(result.current.onFilterSelect).toBeUndefined(); + + act(() => { + result.current.setOnFilterSelect(onFilterSelectMock); + result.current.selectFilter(mockFilter); + }); + + await waitFor(() => { + expect(onFilterSelectMock).toBeDefined(); + expect(onFilterSelectMock).toHaveBeenCalled(); + }); + }); + + it('should handle scopeId undefined on initial values', () => { + // eslint-disable-next-line no-console + console.error = jest.fn(); + + const renderFunction = () => { + renderHook(() => useFilterDropdown(), renderHookConfig); + }; + + expect(renderFunction).toThrow(Error); + expect(renderFunction).toThrow( + 'Scope id is not provided and cannot be found in context.', + ); + }); + + it('should scopeId have been defined on initial values', () => { + const { result } = renderHook( + () => useFilterDropdown({ filterDropdownId }), + renderHookConfig, + ); + + expect(result.current.scopeId).toBeDefined(); + }); +}); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.tsx new file mode 100644 index 000000000..5b416e2e0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandLabel.test.tsx @@ -0,0 +1,48 @@ +import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; +import { capitalize } from '~/utils/string/capitalize'; + +import { getOperandLabel, getOperandLabelShort } from '../getOperandLabel'; + +describe('getOperandLabel', () => { + const testCases = [ + [ViewFilterOperand.Contains, 'Contains'], + [ViewFilterOperand.DoesNotContain, "Doesn't contain"], + [ViewFilterOperand.GreaterThan, 'Greater than'], + [ViewFilterOperand.LessThan, 'Less than'], + [ViewFilterOperand.Is, 'Is'], + [ViewFilterOperand.IsNot, 'Is not'], + [ViewFilterOperand.IsNotNull, 'Is not null'], + [undefined, ''], // undefined operand + ]; + + testCases.forEach(([operand, expectedLabel]) => { + const formattedOperand = capitalize(operand || 'undefined'); + + it(`should return correct label for ViewFilterOperand.${formattedOperand}`, () => { + const result = getOperandLabel(operand as ViewFilterOperand); + expect(result).toBe(expectedLabel); + }); + }); +}); + +describe('getOperandLabelShort', () => { + const testCases = [ + [ViewFilterOperand.Is, ': '], + [ViewFilterOperand.Contains, ': '], + [ViewFilterOperand.IsNot, ': Not'], + [ViewFilterOperand.DoesNotContain, ': Not'], + [ViewFilterOperand.IsNotNull, ': NotNull'], + [ViewFilterOperand.GreaterThan, '\u00A0> '], + [ViewFilterOperand.LessThan, '\u00A0< '], + [undefined, ': '], // undefined operand + ]; + + testCases.forEach(([operand, expectedLabel]) => { + const formattedOperand = capitalize(operand || 'undefined'); + + it(`should return correct short label for ViewFilterOperand.${formattedOperand}`, () => { + const result = getOperandLabelShort(operand as ViewFilterOperand); + expect(result).toBe(expectedLabel); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx new file mode 100644 index 000000000..1486146d8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.tsx @@ -0,0 +1,30 @@ +import { FilterType } from '@/object-record/object-filter-dropdown/types/FilterType'; +import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; + +import { getOperandsForFilterType } from '../getOperandsForFilterType'; + +describe('getOperandsForFilterType', () => { + const testCases = [ + ['TEXT', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], + ['EMAIL', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], + [ + 'FULL_NAME', + [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain], + ], + ['LINK', [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain]], + ['CURRENCY', [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]], + ['NUMBER', [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]], + ['DATE_TIME', [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan]], + ['RELATION', [ViewFilterOperand.Is, ViewFilterOperand.IsNot]], + [undefined, []], + [null, []], + ['UNKNOWN_TYPE', []], + ]; + + testCases.forEach(([filterType, expectedOperands]) => { + it(`should return correct operands for FilterType.${filterType}`, () => { + const result = getOperandsForFilterType(filterType as FilterType); + expect(result).toEqual(expectedOperands); + }); + }); +});