diff --git a/src/CONST.ts b/src/CONST.ts index cf9e5d8a2886..2e70ef284dcd 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -6445,6 +6445,7 @@ const CONST = { MIGRATED_USER_WELCOME_MODAL: 'migratedUserWelcomeModal', + BASE_LIST_ITEM_TEST_ID: 'base-list-item-', PRODUCT_TRAINING_TOOLTIP_NAMES: { CONCEIRGE_LHN_GBR: 'conciergeLHNGBR', RENAME_SAVED_SEARCH: 'renameSavedSearch', diff --git a/src/components/SelectionList/BaseListItem.tsx b/src/components/SelectionList/BaseListItem.tsx index 38df5efaee7b..57fd457b4b00 100644 --- a/src/components/SelectionList/BaseListItem.tsx +++ b/src/components/SelectionList/BaseListItem.tsx @@ -108,6 +108,8 @@ function BaseListItem({ wrapperStyle={pressableWrapperStyle} > ( isFocused, }); + useEffect(() => { + const selectedItemIndex = flattenedSections.allOptions.findIndex((option) => option.isSelected); + if (selectedItemIndex === -1 || selectedItemIndex === focusedIndex) { + return; + } + setFocusedIndex(selectedItemIndex); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [flattenedSections]); + const clearInputAfterSelect = useCallback(() => { onChangeText?.(''); }, [onChangeText]); diff --git a/tests/unit/BaseSelectionListTest.tsx b/tests/unit/BaseSelectionListTest.tsx new file mode 100644 index 000000000000..cf5581e536a3 --- /dev/null +++ b/tests/unit/BaseSelectionListTest.tsx @@ -0,0 +1,67 @@ +import {fireEvent, render, screen} from '@testing-library/react-native'; +import BaseSelectionList from '@components/SelectionList/BaseSelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import type Navigation from '@libs/Navigation/Navigation'; +import CONST from '@src/CONST'; + +type BaseSelectionListSections = { + sections: TItem[]; +}; + +const mockSections = Array.from({length: 10}, (_, index) => ({ + text: `Item ${index}`, + keyForList: `${index}`, + isSelected: index === 1, +})); + +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useIsFocused: jest.fn(), + useFocusEffect: jest.fn(), + }; +}); + +describe('BaseSelectionList', () => { + const onSelectRowMock = jest.fn(); + + function BaseListItemRenderer(props: BaseSelectionListSections) { + const {sections} = props; + const focusedKey = sections.find((item) => item.isSelected)?.keyForList; + return ( + + ); + } + + it('should handle item press correctly', () => { + render(); + fireEvent.press(screen.getByTestId(`${CONST.BASE_LIST_ITEM_TEST_ID}1`)); + expect(onSelectRowMock).toHaveBeenCalledWith({ + ...mockSections.at(1), + shouldAnimateInHighlight: false, + }); + }); + + it('should update focused item when sections are updated from BE', () => { + const updatedMockSections = mockSections.map((section) => ({ + ...section, + isSelected: section.keyForList === '2', + })); + const {rerender} = render(); + expect(screen.getByTestId(`${CONST.BASE_LIST_ITEM_TEST_ID}1`)).toHaveAccessibilityState({ + selected: true, + }); + rerender(); + expect(screen.getByTestId(`${CONST.BASE_LIST_ITEM_TEST_ID}2`)).toHaveAccessibilityState({ + selected: true, + }); + }); +});