diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 685f14201a98..62a66505c70f 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -3623,6 +3623,15 @@ const ROUTES = { return `workspaces/${policyID}/accounting/netsuite/import/custom-list/new/${subPage}${action ? `/${action}` : ''}` as const; }, }, + POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR: { + route: 'workspaces/:policyID/accounting/netsuite/import/custom-list/list-selector', + getRoute: (policyID: string | undefined) => { + if (!policyID) { + Log.warn('Invalid policyID is used to build the POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR route'); + } + return `workspaces/${policyID}/accounting/netsuite/import/custom-list/list-selector` as const; + }, + }, POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD: { route: 'workspaces/:policyID/accounting/netsuite/import/custom-segment/new/:subPage?/:action?', getRoute: (policyID: string | undefined, subPage?: string, action?: 'edit') => { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 9fe35bd517f7..214f54f75121 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -629,6 +629,7 @@ const SCREENS = { NETSUITE_IMPORT_CUSTOM_FIELD_VIEW: 'Policy_Accounting_NetSuite_Import_Custom_Field_View', NETSUITE_IMPORT_CUSTOM_FIELD_EDIT: 'Policy_Accounting_NetSuite_Import_Custom_Field_Edit', NETSUITE_IMPORT_CUSTOM_LIST_ADD: 'Policy_Accounting_NetSuite_Import_Custom_List_Add', + NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR: 'Policy_Accounting_NetSuite_Import_Custom_List_Selector', NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD: 'Policy_Accounting_NetSuite_Import_Custom_Segment_Add', NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS: 'Policy_Accounting_NetSuite_Import_CustomersOrProjects', NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT: 'Policy_Accounting_NetSuite_Import_CustomersOrProjects_Select', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 3bc6d27d9bbe..107c95e2a73d 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -806,6 +806,8 @@ const SettingsModalStackNavigator = createModalStackNavigator('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldEdit').default, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD]: () => require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomListPage').default, + [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR]: () => + require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorPage').default, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD]: () => require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomSegmentPage').default, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS]: () => diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 1efa9b448f7b..aab1c746c1c9 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -119,6 +119,7 @@ const WORKSPACE_TO_RHP: Partial['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_VIEW.route}, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_EDIT.route}, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_LIST_ADD.route}, + [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR.route}, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD.route}, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS.route}, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT.route}, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index d3fe8919e11c..fafa8bbbe1c6 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -959,6 +959,9 @@ type SettingsNavigatorParamList = { subPage?: string; action?: 'edit'; }; + [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR]: { + policyID: string; + }; [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD]: { policyID: string; subPage?: string; diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListPicker.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListPicker.tsx index 6d2887b2daba..748cf7eb0181 100644 --- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListPicker.tsx +++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListPicker.tsx @@ -1,65 +1,38 @@ -import React, {useState} from 'react'; +import React from 'react'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; -import type {CustomListSelectorType} from '@pages/workspace/accounting/netsuite/types'; import CONST from '@src/CONST'; -import type {Policy} from '@src/types/onyx'; -import NetSuiteCustomListSelectorModal from './NetSuiteCustomListSelectorModal'; +import ROUTES from '@src/ROUTES'; type NetSuiteCustomListPickerProps = { /** Current value of the selected item */ value?: string; - /** Current connected policy */ - policy?: Policy; - - /** Callback when the list item is selected */ - onInputChange?: (value: string, key?: string) => void; - - /** Id of the internalID input to be updated on input change */ - internalIDInputID?: string; + /** Policy ID from the parent route's URL params (preferred over policy?.id because it is set before the Onyx policy record hydrates) */ + policyID?: string; /** Form Error description */ errorText?: string; }; -function NetSuiteCustomListPicker({value, policy, internalIDInputID, errorText, onInputChange = () => {}}: NetSuiteCustomListPickerProps) { +function NetSuiteCustomListPicker({value, policyID, errorText}: NetSuiteCustomListPickerProps) { const {translate} = useLocalize(); - const [isPickerVisible, setIsPickerVisible] = useState(false); - - const hidePickerModal = () => { - setIsPickerVisible(false); - }; - - const updateInput = (item: CustomListSelectorType) => { - onInputChange?.(item.value); - if (internalIDInputID) { - onInputChange(item.id, internalIDInputID); - } - hidePickerModal(); - }; return ( - <> - setIsPickerVisible(true)} - brickRoadIndicator={errorText ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - errorText={errorText} - /> - - + { + if (!policyID) { + return; + } + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR.getRoute(policyID)); + }} + brickRoadIndicator={errorText ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + errorText={errorText} + /> ); } diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorModal.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorPage.tsx similarity index 59% rename from src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorModal.tsx rename to src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorPage.tsx index 014fd0f0136c..0e42f15365d8 100644 --- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorModal.tsx +++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorPage.tsx @@ -1,41 +1,36 @@ import {Str} from 'expensify-common'; import React, {useMemo} from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import Modal from '@components/Modal'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import SingleSelectListItem from '@components/SelectionList/ListItem/SingleSelectListItem'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import usePolicy from '@hooks/usePolicy'; +import {setDraftValues} from '@libs/actions/FormActions'; +import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {CustomListSelectorType} from '@pages/workspace/accounting/netsuite/types'; import CONST from '@src/CONST'; -import type {Policy} from '@src/types/onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import INPUT_IDS from '@src/types/form/NetSuiteCustomFieldForm'; -type NetSuiteCustomListSelectorModalProps = { - /** Whether the modal is visible */ - isVisible: boolean; +type NetSuiteCustomListSelectorPageProps = PlatformStackScreenProps; - /** Function to call when the user closes the business type selector modal */ - onClose: () => void; - - /** Label to display on field */ - label: string; - - /** Custom List value selected */ - currentCustomListValue: string; - - policy?: Policy; - - /** Function to call when the user selects a custom list */ - onCustomListSelected: (value: CustomListSelectorType) => void; - - /** Function to call when the user presses on the modal backdrop */ - onBackdropPress?: () => void; -}; - -function NetSuiteCustomListSelectorModal({isVisible, currentCustomListValue, onCustomListSelected, onClose, label, policy, onBackdropPress}: NetSuiteCustomListSelectorModalProps) { +function NetSuiteCustomListSelectorPage({ + route: { + params: {policyID}, + }, +}: NetSuiteCustomListSelectorPageProps) { const {translate} = useLocalize(); const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); + const policy = usePolicy(policyID); + const [formDraft] = useOnyx(ONYXKEYS.FORMS.NETSUITE_CUSTOM_LIST_ADD_FORM_DRAFT); + const currentCustomListValue = formDraft?.[INPUT_IDS.LIST_NAME] ?? ''; const rawCustomLists = policy?.connections?.netsuite?.options?.data?.customLists; @@ -69,29 +64,36 @@ function NetSuiteCustomListSelectorModal({isVisible, currentCustomListValue, onC [searchValue, showTextInput, translate, setSearchValue, debouncedSearchValue, options.length], ); + const label = translate('workspace.netsuite.import.importCustomFields.customLists.fields.listName'); + + const onSelectRow = (item: CustomListSelectorType) => { + setDraftValues(ONYXKEYS.FORMS.NETSUITE_CUSTOM_LIST_ADD_FORM, { + [INPUT_IDS.LIST_NAME]: item.value, + [INPUT_IDS.INTERNAL_ID]: item.id, + }); + Navigation.goBack(); + }; + return ( - Navigation.goBack()} /> - + ); } -export default NetSuiteCustomListSelectorModal; +NetSuiteCustomListSelectorPage.displayName = 'NetSuiteCustomListSelectorPage'; + +export default NetSuiteCustomListSelectorPage; diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomListContent.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomListContent.tsx index 1cf833446c7a..e002af31ce8e 100644 --- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomListContent.tsx +++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomListContent.tsx @@ -140,6 +140,7 @@ function NetSuiteImportAddCustomListContent({policy, draftValues, policyIDParam} onNext={handleNextScreen} onMove={moveTo} policy={policy} + policyIDParam={policyIDParam} importCustomField={CONST.NETSUITE_CONFIG.IMPORT_CUSTOM_FIELDS.CUSTOM_LISTS} netSuiteCustomFieldFormValues={values} customLists={customLists} diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomSegmentContent.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomSegmentContent.tsx index d61b5a76c244..f985159982e4 100644 --- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomSegmentContent.tsx +++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteImportAddCustomSegmentContent.tsx @@ -145,6 +145,7 @@ function NetSuiteImportAddCustomSegmentContent({policy, policyIDParam, draftValu onNext={handleNextScreen} onMove={moveTo} policy={policy} + policyIDParam={policyIDParam} importCustomField={CONST.NETSUITE_CONFIG.IMPORT_CUSTOM_FIELDS.CUSTOM_SEGMENTS} customSegmentType={customSegmentType} setCustomSegmentType={setCustomSegmentType} diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/subPages/ChooseCustomListStep.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/subPages/ChooseCustomListStep.tsx index de58b07829a1..a3603274afd8 100644 --- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/subPages/ChooseCustomListStep.tsx +++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/subPages/ChooseCustomListStep.tsx @@ -14,7 +14,7 @@ import INPUT_IDS from '@src/types/form/NetSuiteCustomFieldForm'; const STEP_FIELDS = [INPUT_IDS.LIST_NAME, INPUT_IDS.INTERNAL_ID]; -function ChooseCustomListStep({policy, onNext, isEditing, netSuiteCustomFieldFormValues}: CustomFieldSubPageWithPolicy) { +function ChooseCustomListStep({policyIDParam, onNext, isEditing, netSuiteCustomFieldFormValues}: CustomFieldSubPageWithPolicy) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -49,8 +49,7 @@ function ChooseCustomListStep({policy, onNext, isEditing, netSuiteCustomFieldFor diff --git a/src/pages/workspace/accounting/netsuite/types.ts b/src/pages/workspace/accounting/netsuite/types.ts index 7825b9743f19..0e2954c0a82f 100644 --- a/src/pages/workspace/accounting/netsuite/types.ts +++ b/src/pages/workspace/accounting/netsuite/types.ts @@ -81,6 +81,9 @@ type CustomFieldSubPageWithPolicy = SubPageProps & { /** Current policy in the form steps */ policy: Policy | undefined; + /** Policy ID from the parent route's URL params (set before the policy Onyx record finishes hydrating) */ + policyIDParam: string | undefined; + /** Whether the page is a custom segment or custom list */ importCustomField: ValueOf; diff --git a/tests/ui/NetSuiteCustomListPickerTest.tsx b/tests/ui/NetSuiteCustomListPickerTest.tsx new file mode 100644 index 000000000000..f5d56ae85927 --- /dev/null +++ b/tests/ui/NetSuiteCustomListPickerTest.tsx @@ -0,0 +1,42 @@ +import {render} from '@testing-library/react-native'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import Navigation from '@libs/Navigation/Navigation'; +import NetSuiteCustomListPicker from '@pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListPicker'; +import ROUTES from '@src/ROUTES'; + +jest.mock('@components/MenuItemWithTopDescription', () => jest.fn(() => null)); +jest.mock('@hooks/useLocalize', () => + jest.fn(() => ({ + translate: (key: string) => key, + })), +); +jest.mock('@libs/Navigation/Navigation', () => ({ + navigate: jest.fn(), +})); + +describe('NetSuiteCustomListPicker', () => { + const mockedMenuItem = jest.mocked(MenuItemWithTopDescription); + const mockedNavigate = jest.mocked(Navigation.navigate); + + beforeEach(() => { + mockedMenuItem.mockClear(); + mockedNavigate.mockClear(); + }); + + it('navigates to the selector route using the route policyID when the picker is pressed', () => { + render(); + + mockedMenuItem.mock.lastCall?.[0].onPress?.({} as never); + + expect(mockedNavigate).toHaveBeenCalledTimes(1); + expect(mockedNavigate).toHaveBeenCalledWith(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_LIST_SELECTOR.getRoute('P1')); + }); + + it('does not navigate when policyID is undefined so an "undefined" deep link is never produced', () => { + render(); + + mockedMenuItem.mock.lastCall?.[0].onPress?.({} as never); + + expect(mockedNavigate).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/ui/NetSuiteCustomListSelectorPageTest.tsx b/tests/ui/NetSuiteCustomListSelectorPageTest.tsx new file mode 100644 index 000000000000..0f08850ffd3d --- /dev/null +++ b/tests/ui/NetSuiteCustomListSelectorPageTest.tsx @@ -0,0 +1,135 @@ +import type * as ReactNavigation from '@react-navigation/native'; +import {act, render} from '@testing-library/react-native'; +import React from 'react'; +import SelectionList from '@components/SelectionList'; +import {setDraftValues} from '@libs/actions/FormActions'; +import Navigation from '@libs/Navigation/Navigation'; +import NetSuiteCustomListSelectorPage from '@pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldNew/NetSuiteCustomListSelectorPage'; +import type {CustomListSelectorType} from '@pages/workspace/accounting/netsuite/types'; +import ONYXKEYS from '@src/ONYXKEYS'; +import INPUT_IDS from '@src/types/form/NetSuiteCustomFieldForm'; + +const mockUseState = React.useState; + +const mockCustomLists = [ + {id: '123', name: 'Department'}, + {id: '456', name: 'Project'}, +]; + +const mockPolicy = { + id: 'P1', + connections: { + netsuite: { + options: { + data: { + customLists: mockCustomLists, + }, + }, + }, + }, +}; + +let mockFormDraft: Record | undefined; + +jest.mock('@react-navigation/native', () => { + const actualNavigation: typeof ReactNavigation = jest.requireActual('@react-navigation/native'); + return { + ...actualNavigation, + useFocusEffect: jest.fn(), + }; +}); + +jest.mock('@components/HeaderWithBackButton', () => jest.fn(() => null)); +jest.mock('@components/ScreenWrapper', () => jest.fn(({children}: {children: React.ReactNode}) => children)); +jest.mock('@components/SelectionList', () => jest.fn(() => null)); +jest.mock('@components/SelectionList/ListItem/SingleSelectListItem', () => jest.fn(() => null)); +jest.mock('@pages/workspace/AccessOrNotFoundWrapper', () => jest.fn(({children}: {children: React.ReactNode}) => children)); +jest.mock('@hooks/useDebouncedState', () => + jest.fn((initialValue: string) => { + const [value, setValue] = mockUseState(initialValue); + return [value, value, setValue]; + }), +); +jest.mock('@hooks/useLocalize', () => + jest.fn(() => ({ + translate: (key: string) => key, + })), +); +jest.mock('@hooks/usePolicy', () => jest.fn(() => mockPolicy)); +jest.mock('@hooks/useOnyx', () => jest.fn(() => [mockFormDraft, {status: 'loaded'}])); +jest.mock('@libs/actions/FormActions', () => ({ + setDraftValues: jest.fn(), +})); +jest.mock('@libs/Navigation/Navigation', () => ({ + goBack: jest.fn(), + navigate: jest.fn(), +})); + +describe('NetSuiteCustomListSelectorPage', () => { + const mockedSelectionList = jest.mocked(SelectionList); + const mockedSetDraftValues = jest.mocked(setDraftValues); + const mockedNavigationGoBack = jest.mocked(Navigation.goBack); + + beforeEach(() => { + mockedSelectionList.mockClear(); + mockedSetDraftValues.mockClear(); + mockedNavigationGoBack.mockClear(); + mockFormDraft = undefined; + }); + + it('builds option rows from the policy custom lists and marks the draft value as selected', () => { + mockFormDraft = {[INPUT_IDS.LIST_NAME]: 'Project'}; + + render( + , + ); + + const selectionListProps = mockedSelectionList.mock.lastCall?.[0]; + expect(selectionListProps?.data).toEqual([ + expect.objectContaining({value: 'Department', isSelected: false, keyForList: 'Department', id: '123'}), + expect.objectContaining({value: 'Project', isSelected: true, keyForList: 'Project', id: '456'}), + ]); + expect(selectionListProps?.initiallyFocusedItemKey).toBe('Project'); + }); + + it('writes both listName and internalID to the form draft on row select then navigates back', () => { + render( + , + ); + + const selectionListProps = mockedSelectionList.mock.lastCall?.[0]; + const selectedRow = selectionListProps?.data.find((item) => (item as CustomListSelectorType).value === 'Department') as CustomListSelectorType; + selectionListProps?.onSelectRow?.(selectedRow); + + expect(mockedSetDraftValues).toHaveBeenCalledWith(ONYXKEYS.FORMS.NETSUITE_CUSTOM_LIST_ADD_FORM, { + [INPUT_IDS.LIST_NAME]: 'Department', + [INPUT_IDS.INTERNAL_ID]: '123', + }); + expect(mockedNavigationGoBack).toHaveBeenCalledTimes(1); + }); + + it('renders an empty option set with a no-results header message when search filters everything out', () => { + render( + , + ); + + const initialProps = mockedSelectionList.mock.lastCall?.[0]; + + act(() => { + initialProps?.textInputOptions?.onChangeText?.('zzzzz'); + }); + + const filteredProps = mockedSelectionList.mock.lastCall?.[0]; + expect(filteredProps?.data).toEqual([]); + expect(filteredProps?.textInputOptions?.headerMessage).toBe('common.noResultsFound'); + }); +});