From 5d80f5fa4da9c3c8226568ac27d024350fc6c86c Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Mon, 11 Dec 2023 12:22:00 +0200 Subject: [PATCH] feat: test filter date item (#5576) --- .../FilterDateItem/FilterDateItem.test.tsx | 81 +++++++++++++++++++ .../common/FilterDateItem/FilterDateItem.tsx | 30 ++++--- .../common/FilterItem/FilterItem.test.tsx | 8 +- .../common/FilterItem/FilterItem.tsx | 6 +- .../FeatureToggleFilters.tsx | 15 ++-- 5 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 frontend/src/component/common/FilterDateItem/FilterDateItem.test.tsx diff --git a/frontend/src/component/common/FilterDateItem/FilterDateItem.test.tsx b/frontend/src/component/common/FilterDateItem/FilterDateItem.test.tsx new file mode 100644 index 0000000000..6e81795a7f --- /dev/null +++ b/frontend/src/component/common/FilterDateItem/FilterDateItem.test.tsx @@ -0,0 +1,81 @@ +import { screen } from '@testing-library/react'; +import { render } from 'utils/testRenderer'; +import { vi } from 'vitest'; +import { FilterItemParams } from '../FilterItem/FilterItem'; +import { FilterDateItem, IFilterDateItemProps } from './FilterDateItem'; + +const getDate = (option: string) => screen.getByText(option); + +const setup = (initialState: FilterItemParams) => { + const recordedChanges: FilterItemParams[] = []; + const mockProps: IFilterDateItemProps = { + label: 'Test Label', + onChange: (value: FilterItemParams) => { + recordedChanges.push(value); + }, + onChipClose: () => {}, + operators: ['IS_ON_OR_AFTER', 'IS_BEFORE'], + state: initialState, + }; + + render(); + + return recordedChanges; +}; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('FilterDateItem Component', () => { + it('renders initial state correctly', async () => { + const mockState = { + operator: 'IS_ON_OR_AFTER', + values: ['2015-01-21'], + }; + + const recordedChanges = setup(mockState); + + const valuesElement = await screen.findByText('01/21/2015'); + await screen.findByText('is on or after'); + expect(valuesElement).toBeInTheDocument(); + + valuesElement.click(); + + const selectedDate = getDate('21'); + + expect(selectedDate).toHaveAttribute('aria-selected', 'true'); + + getDate('22').click(); + + expect(recordedChanges).toEqual([ + { + operator: 'IS_ON_OR_AFTER', + values: ['2015-01-22'], + }, + ]); + }); + + it('switches operator', async () => { + const mockState = { + operator: 'IS_ON_OR_AFTER', + values: ['2020-01-01'], + }; + + const recordedChanges = setup(mockState); + + const operatorsElement = await screen.findByText('is on or after'); + + operatorsElement.click(); + const newOperator = await screen.findByText('is before'); + + newOperator.click(); + + expect(recordedChanges).toEqual([ + { + operator: 'IS_BEFORE', + values: ['2020-01-01'], + }, + ]); + }); +}); diff --git a/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx b/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx index 1339f20db7..95425e7b1d 100644 --- a/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx +++ b/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx @@ -2,18 +2,18 @@ import { Box } from '@mui/material'; import React, { FC, useEffect, useRef, useState } from 'react'; import { StyledPopover } from '../FilterItem/FilterItem.styles'; import { FilterItemChip } from '../FilterItem/FilterItemChip/FilterItemChip'; -import { FilterItem } from '../FilterItem/FilterItem'; import { DateCalendar, LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { format } from 'date-fns'; import { useLocationSettings } from 'hooks/useLocationSettings'; import { getLocalizedDateString } from '../util'; +import { FilterItemParams } from '../FilterItem/FilterItem'; -interface IFilterDateItemProps { +export interface IFilterDateItemProps { label: string; - onChange: (value: FilterItem | undefined) => void; + onChange: (value: FilterItemParams) => void; onChipClose: () => void; - state: FilterItem | null | undefined; + state: FilterItemParams | null | undefined; operators: [string, ...string[]]; } @@ -47,16 +47,11 @@ export const FilterDateItem: FC = ({ const selectedDate = state ? new Date(state.values[0]) : null; const currentOperator = state ? state.operator : operators[0]; const onDelete = () => { - onChange(undefined); + onChange({ operator: operators[0], values: [] }); onClose(); onChipClose(); }; - const setValue = (value: Date | null) => { - const formattedValue = value ? format(value, 'yyyy-MM-dd') : ''; - onChange({ operator: currentOperator, values: [formattedValue] }); - }; - useEffect(() => { if (state && !operators.includes(state.operator)) { onChange({ @@ -77,7 +72,10 @@ export const FilterDateItem: FC = ({ operator={currentOperator} operatorOptions={operators} onChangeOperator={(operator) => { - onChange({ operator, values: selectedOptions ?? [] }); + const formattedValue = selectedDate + ? format(selectedDate, 'yyyy-MM-dd') + : ''; + onChange({ operator, values: [formattedValue] ?? [] }); }} /> @@ -98,7 +96,15 @@ export const FilterDateItem: FC = ({ setValue(newValue)} + onChange={(value) => { + const formattedValue = value + ? format(value, 'yyyy-MM-dd') + : ''; + onChange({ + operator: currentOperator, + values: [formattedValue], + }); + }} /> diff --git a/frontend/src/component/common/FilterItem/FilterItem.test.tsx b/frontend/src/component/common/FilterItem/FilterItem.test.tsx index d44392002b..b4e3793750 100644 --- a/frontend/src/component/common/FilterItem/FilterItem.test.tsx +++ b/frontend/src/component/common/FilterItem/FilterItem.test.tsx @@ -1,12 +1,12 @@ import { screen } from '@testing-library/react'; import { render } from 'utils/testRenderer'; -import { FilterItem, IFilterItemProps } from './FilterItem'; +import { FilterItem, FilterItemParams, IFilterItemProps } from './FilterItem'; const getOption = (option: string) => screen.getByText(option).closest('li')!.querySelector('input')!; -const setup = (initialState: FilterItem) => { - const recordedChanges: FilterItem[] = []; +const setup = (initialState: FilterItemParams) => { + const recordedChanges: FilterItemParams[] = []; const mockProps: IFilterItemProps = { label: 'Test Label', options: [ @@ -23,7 +23,7 @@ const setup = (initialState: FilterItem) => { value: '3', }, ], - onChange: (value: FilterItem) => { + onChange: (value: FilterItemParams) => { recordedChanges.push(value); }, onChipClose: () => {}, diff --git a/frontend/src/component/common/FilterItem/FilterItem.tsx b/frontend/src/component/common/FilterItem/FilterItem.tsx index 86012e80ca..1502a427ae 100644 --- a/frontend/src/component/common/FilterItem/FilterItem.tsx +++ b/frontend/src/component/common/FilterItem/FilterItem.tsx @@ -13,14 +13,14 @@ import { FilterItemChip } from './FilterItemChip/FilterItemChip'; export interface IFilterItemProps { label: string; options: Array<{ label: string; value: string }>; - onChange: (value: FilterItem) => void; + onChange: (value: FilterItemParams) => void; onChipClose: () => void; - state: FilterItem | null | undefined; + state: FilterItemParams | null | undefined; singularOperators: [string, ...string[]]; pluralOperators: [string, ...string[]]; } -export type FilterItem = { +export type FilterItemParams = { operator: string; values: string[]; }; diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleFilters/FeatureToggleFilters.tsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleFilters/FeatureToggleFilters.tsx index f39065f50e..55fe341d34 100644 --- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleFilters/FeatureToggleFilters.tsx +++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleFilters/FeatureToggleFilters.tsx @@ -1,11 +1,14 @@ import { useEffect, useState, VFC } from 'react'; import { Box, styled } from '@mui/material'; -import { FilterItem } from 'component/common/FilterItem/FilterItem'; import useProjects from 'hooks/api/getters/useProjects/useProjects'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import AddFilterButton from './AddFilterButton'; import { useSegments } from 'hooks/api/getters/useSegments/useSegments'; -import { FilterDateItem } from '../../../common/FilterDateItem/FilterDateItem'; +import { FilterDateItem } from 'component/common/FilterDateItem/FilterDateItem'; +import { + FilterItem, + FilterItemParams, +} from 'component/common/FilterItem/FilterItem'; const StyledBox = styled(Box)(({ theme }) => ({ display: 'flex', @@ -14,10 +17,10 @@ const StyledBox = styled(Box)(({ theme }) => ({ })); export type FeatureTogglesListFilters = { - project?: FilterItem | null | undefined; - state?: FilterItem | null | undefined; - segment?: FilterItem | null | undefined; - createdAt?: FilterItem | null | undefined; + project?: FilterItemParams | null | undefined; + state?: FilterItemParams | null | undefined; + segment?: FilterItemParams | null | undefined; + createdAt?: FilterItemParams | null | undefined; }; interface IFeatureToggleFiltersProps {