diff --git a/src/pages/home/ForYouSection/index.tsx b/src/pages/home/ForYouSection/index.tsx index cf86ac528b90d..be98abd0e9a07 100644 --- a/src/pages/home/ForYouSection/index.tsx +++ b/src/pages/home/ForYouSection/index.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useMemo} from 'react'; +import React from 'react'; import {View} from 'react-native'; import ActivityIndicator from '@components/ActivityIndicator'; import BaseWidgetItem from '@components/BaseWidgetItem'; @@ -15,7 +15,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import {accountIDSelector} from '@src/selectors/Session'; -import todosReportCountsSelector, {EMPTY_TODOS_SINGLE_REPORT_IDS, todosSingleReportIDsSelector} from '@src/selectors/Todos'; +import todosReportCountsSelector from '@src/selectors/Todos'; import EmptyState from './EmptyState'; function ForYouSection() { @@ -26,7 +26,6 @@ function ForYouSection() { const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector}); const [isLoadingApp = true] = useOnyx(ONYXKEYS.IS_LOADING_APP); const [reportCounts = CONST.EMPTY_TODOS_REPORT_COUNTS] = useOnyx(ONYXKEYS.DERIVED.TODOS, {selector: todosReportCountsSelector}); - const [singleReportIDs = EMPTY_TODOS_SINGLE_REPORT_IDS] = useOnyx(ONYXKEYS.DERIVED.TODOS, {selector: todosSingleReportIDsSelector}); const icons = useMemoizedLazyExpensifyIcons(['MoneyBag', 'Send', 'ThumbsUp', 'Export']); @@ -37,72 +36,48 @@ function ForYouSection() { const hasAnyTodos = submitCount > 0 || approveCount > 0 || payCount > 0 || exportCount > 0; - const createNavigationHandler = useCallback( - (action: string, queryParams: Record, reportID?: string) => () => { - if (reportID) { - if (shouldUseNarrowLayout) { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID)); - } else { - Navigation.navigate(ROUTES.EXPENSE_REPORT_RHP.getRoute({reportID})); - } - return; - } - - Navigation.navigate( - ROUTES.SEARCH_ROOT.getRoute({ - query: buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, - action, - ...queryParams, - }), + const createNavigationHandler = (action: string, queryParams: Record) => () => { + Navigation.navigate( + ROUTES.SEARCH_ROOT.getRoute({ + query: buildQueryStringFromFilterFormValues({ + type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + action, + ...queryParams, }), - ); - }, - [shouldUseNarrowLayout], - ); + }), + ); + }; - const todoItems = useMemo( - () => - [ - { - key: 'submit', - count: submitCount, - icon: icons.Send, - translationKey: 'homePage.forYouSection.submit' as const, - handler: createNavigationHandler(CONST.SEARCH.ACTION_FILTERS.SUBMIT, {from: [`${accountID}`]}, singleReportIDs[CONST.SEARCH.SEARCH_KEYS.SUBMIT]), - }, - { - key: 'approve', - count: approveCount, - icon: icons.ThumbsUp, - translationKey: 'homePage.forYouSection.approve' as const, - handler: createNavigationHandler(CONST.SEARCH.ACTION_FILTERS.APPROVE, {to: [`${accountID}`]}, singleReportIDs[CONST.SEARCH.SEARCH_KEYS.APPROVE]), - }, - { - key: 'pay', - count: payCount, - icon: icons.MoneyBag, - translationKey: 'homePage.forYouSection.pay' as const, - handler: createNavigationHandler( - CONST.SEARCH.ACTION_FILTERS.PAY, - {reimbursable: CONST.SEARCH.BOOLEAN.YES, payer: accountID?.toString()}, - singleReportIDs[CONST.SEARCH.SEARCH_KEYS.PAY], - ), - }, - { - key: 'export', - count: exportCount, - icon: icons.Export, - translationKey: 'homePage.forYouSection.export' as const, - handler: createNavigationHandler( - CONST.SEARCH.ACTION_FILTERS.EXPORT, - {exporter: [`${accountID}`], exportedOn: CONST.SEARCH.DATE_PRESETS.NEVER}, - singleReportIDs[CONST.SEARCH.SEARCH_KEYS.EXPORT], - ), - }, - ].filter((item) => item.count > 0), - [accountID, approveCount, createNavigationHandler, exportCount, icons.Export, icons.MoneyBag, icons.Send, icons.ThumbsUp, payCount, singleReportIDs, submitCount], - ); + const todoItems = [ + { + key: 'submit', + count: submitCount, + icon: icons.Send, + translationKey: 'homePage.forYouSection.submit' as const, + handler: createNavigationHandler(CONST.SEARCH.ACTION_FILTERS.SUBMIT, {from: [`${accountID}`]}), + }, + { + key: 'approve', + count: approveCount, + icon: icons.ThumbsUp, + translationKey: 'homePage.forYouSection.approve' as const, + handler: createNavigationHandler(CONST.SEARCH.ACTION_FILTERS.APPROVE, {to: [`${accountID}`]}), + }, + { + key: 'pay', + count: payCount, + icon: icons.MoneyBag, + translationKey: 'homePage.forYouSection.pay' as const, + handler: createNavigationHandler(CONST.SEARCH.ACTION_FILTERS.PAY, {reimbursable: CONST.SEARCH.BOOLEAN.YES, payer: accountID?.toString()}), + }, + { + key: 'export', + count: exportCount, + icon: icons.Export, + translationKey: 'homePage.forYouSection.export' as const, + handler: createNavigationHandler(CONST.SEARCH.ACTION_FILTERS.EXPORT, {exporter: [`${accountID}`], exportedOn: CONST.SEARCH.DATE_PRESETS.NEVER}), + }, + ].filter((item) => item.count > 0); const renderTodoItems = () => ( diff --git a/src/selectors/Todos.ts b/src/selectors/Todos.ts index 9c15ae49c35f2..78b9c0f93a473 100644 --- a/src/selectors/Todos.ts +++ b/src/selectors/Todos.ts @@ -1,15 +1,7 @@ -import {shallowEqual} from 'fast-equals'; import type {OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {TodosDerivedValue} from '@src/types/onyx'; -const EMPTY_TODOS_SINGLE_REPORT_IDS = Object.freeze({ - submit: undefined, - approve: undefined, - pay: undefined, - export: undefined, -}); - const todosReportCountsSelector = (todos: OnyxEntry) => { if (!todos) { return CONST.EMPTY_TODOS_REPORT_COUNTS; @@ -23,44 +15,4 @@ const todosReportCountsSelector = (todos: OnyxEntry) => { }; }; -type SingleReportIDs = { - [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: string | undefined; - [CONST.SEARCH.SEARCH_KEYS.APPROVE]: string | undefined; - [CONST.SEARCH.SEARCH_KEYS.PAY]: string | undefined; - [CONST.SEARCH.SEARCH_KEYS.EXPORT]: string | undefined; -}; - -let previousSingleReportIDs: SingleReportIDs = EMPTY_TODOS_SINGLE_REPORT_IDS as SingleReportIDs; - -const todosSingleReportIDsSelector = (todos: OnyxEntry) => { - if (!todos) { - return EMPTY_TODOS_SINGLE_REPORT_IDS; - } - - const submitReportID = todos.reportsToSubmit.length === 1 ? todos.reportsToSubmit.at(0)?.reportID : undefined; - const approveReportID = todos.reportsToApprove.length === 1 ? todos.reportsToApprove.at(0)?.reportID : undefined; - const payReportID = todos.reportsToPay.length === 1 ? todos.reportsToPay.at(0)?.reportID : undefined; - const exportReportID = todos.reportsToExport.length === 1 ? todos.reportsToExport.at(0)?.reportID : undefined; - - if (!submitReportID && !approveReportID && !payReportID && !exportReportID) { - previousSingleReportIDs = EMPTY_TODOS_SINGLE_REPORT_IDS; - return EMPTY_TODOS_SINGLE_REPORT_IDS; - } - - const newValue = { - [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: submitReportID, - [CONST.SEARCH.SEARCH_KEYS.APPROVE]: approveReportID, - [CONST.SEARCH.SEARCH_KEYS.PAY]: payReportID, - [CONST.SEARCH.SEARCH_KEYS.EXPORT]: exportReportID, - }; - - if (shallowEqual(previousSingleReportIDs, newValue)) { - return previousSingleReportIDs; - } - - previousSingleReportIDs = newValue; - return newValue; -}; - export default todosReportCountsSelector; -export {todosSingleReportIDsSelector, EMPTY_TODOS_SINGLE_REPORT_IDS}; diff --git a/tests/ui/ForYouSectionTest.tsx b/tests/ui/ForYouSectionTest.tsx deleted file mode 100644 index f2f358bac0e79..0000000000000 --- a/tests/ui/ForYouSectionTest.tsx +++ /dev/null @@ -1,324 +0,0 @@ -import {act, fireEvent, render, screen} from '@testing-library/react-native'; -import React from 'react'; -import Onyx from 'react-native-onyx'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import Navigation from '@libs/Navigation/Navigation'; -import ForYouSection from '@pages/home/ForYouSection'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import type {TodosDerivedValue} from '@src/types/onyx'; -import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; - -jest.mock('@libs/Navigation/Navigation', () => ({ - navigate: jest.fn(), -})); - -jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); - -jest.mock('@hooks/useLocalize', () => - jest.fn(() => ({ - translate: jest.fn((key: string, params?: Record) => { - if (key === 'homePage.forYouSection.begin') { - return 'Begin'; - } - return params ? `${key}:${JSON.stringify(params)}` : key; - }), - numberFormat: jest.fn((num: number) => num.toString()), - localeCompare: jest.fn((a: string, b: string) => a.localeCompare(b)), - })), -); - -jest.mock('@hooks/useThemeStyles', () => - jest.fn( - () => - new Proxy( - {}, - { - get: () => jest.fn(() => ({})), - }, - ), - ), -); - -jest.mock('@hooks/useTheme', () => jest.fn(() => ({}))); - -jest.mock('@hooks/useLazyAsset', () => ({ - useMemoizedLazyExpensifyIcons: jest.fn(() => ({ - MoneyBag: null, - Send: null, - ThumbsUp: null, - Export: null, - })), - useMemoizedLazyIllustrations: jest.fn(() => ({ - ThumbsUpStars: null, - Fireworks: null, - })), -})); - -jest.mock('react-native-reanimated', () => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return require('react-native-reanimated/mock'); -}); - -const mockNavigate = jest.mocked(Navigation.navigate); -const mockUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; - -const ACCOUNT_ID = 12345; - -const BASE_TODOS: TodosDerivedValue = { - reportsToSubmit: [], - reportsToApprove: [], - reportsToPay: [], - reportsToExport: [], - transactionsByReportID: {}, -}; - -function renderForYouSection() { - return render(); -} - -function pressFirstBeginButton() { - const [firstButton] = screen.getAllByText('Begin'); - fireEvent.press(firstButton); -} - -describe('ForYouSection', () => { - beforeAll(() => { - Onyx.init({keys: ONYXKEYS}); - }); - - beforeEach(async () => { - mockUseResponsiveLayout.mockReturnValue({ - shouldUseNarrowLayout: false, - isSmallScreenWidth: false, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: true, - isExtraLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: false, - onboardingIsMediumOrLargerScreenWidth: true, - }); - - await act(async () => { - await Onyx.multiSet({ - [ONYXKEYS.SESSION]: {accountID: ACCOUNT_ID, email: 'test@example.com'}, - [ONYXKEYS.IS_LOADING_APP]: false, - }); - }); - await waitForBatchedUpdatesWithAct(); - }); - - afterEach(async () => { - jest.clearAllMocks(); - await act(async () => { - await Onyx.clear(); - }); - await waitForBatchedUpdatesWithAct(); - }); - - describe('EmptyState', () => { - it('renders EmptyState when there are no todos', async () => { - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, BASE_TODOS); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - expect(screen.queryByText('Begin')).not.toBeOnTheScreen(); - }); - }); - - describe('navigation with multiple reports (search route)', () => { - it('navigates to SEARCH_ROOT when submit has multiple reports', async () => { - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToSubmit: [{reportID: '1'} as TodosDerivedValue['reportsToSubmit'][number], {reportID: '2'} as TodosDerivedValue['reportsToSubmit'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - const calledRoute = mockNavigate.mock.calls.at(0)?.at(0) as string; - expect(calledRoute).toContain(ROUTES.SEARCH_ROOT.route); - }); - - it('navigates to SEARCH_ROOT when approve has multiple reports', async () => { - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToApprove: [{reportID: '3'} as TodosDerivedValue['reportsToApprove'][number], {reportID: '4'} as TodosDerivedValue['reportsToApprove'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - const calledRoute = mockNavigate.mock.calls.at(0)?.at(0) as string; - expect(calledRoute).toContain(ROUTES.SEARCH_ROOT.route); - }); - }); - - describe('navigation with a single report (direct report route)', () => { - describe('wide layout', () => { - beforeEach(() => { - mockUseResponsiveLayout.mockReturnValue({ - shouldUseNarrowLayout: false, - isSmallScreenWidth: false, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: true, - isExtraLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: false, - onboardingIsMediumOrLargerScreenWidth: true, - }); - }); - - it('navigates to EXPENSE_REPORT_RHP when submit has exactly one report on wide layout', async () => { - const reportID = '42'; - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToSubmit: [{reportID} as TodosDerivedValue['reportsToSubmit'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - expect(mockNavigate).toHaveBeenCalledWith(ROUTES.EXPENSE_REPORT_RHP.getRoute({reportID})); - }); - - it('navigates to EXPENSE_REPORT_RHP when approve has exactly one report on wide layout', async () => { - const reportID = '55'; - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToApprove: [{reportID} as TodosDerivedValue['reportsToApprove'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - expect(mockNavigate).toHaveBeenCalledWith(ROUTES.EXPENSE_REPORT_RHP.getRoute({reportID})); - }); - - it('navigates to EXPENSE_REPORT_RHP when pay has exactly one report on wide layout', async () => { - const reportID = '66'; - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToPay: [{reportID} as TodosDerivedValue['reportsToPay'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - expect(mockNavigate).toHaveBeenCalledWith(ROUTES.EXPENSE_REPORT_RHP.getRoute({reportID})); - }); - - it('navigates to EXPENSE_REPORT_RHP when export has exactly one report on wide layout', async () => { - const reportID = '77'; - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToExport: [{reportID} as TodosDerivedValue['reportsToExport'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - expect(mockNavigate).toHaveBeenCalledWith(ROUTES.EXPENSE_REPORT_RHP.getRoute({reportID})); - }); - }); - - describe('narrow layout', () => { - beforeEach(() => { - mockUseResponsiveLayout.mockReturnValue({ - shouldUseNarrowLayout: true, - isSmallScreenWidth: true, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: false, - isExtraLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: true, - onboardingIsMediumOrLargerScreenWidth: false, - }); - }); - - it('navigates to REPORT_WITH_ID when submit has exactly one report on narrow layout', async () => { - const reportID = '99'; - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToSubmit: [{reportID} as TodosDerivedValue['reportsToSubmit'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - expect(mockNavigate).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(reportID)); - }); - - it('navigates to REPORT_WITH_ID when approve has exactly one report on narrow layout', async () => { - const reportID = '100'; - await act(async () => { - await Onyx.set(ONYXKEYS.DERIVED.TODOS, { - ...BASE_TODOS, - reportsToApprove: [{reportID} as TodosDerivedValue['reportsToApprove'][number]], - }); - }); - await waitForBatchedUpdatesWithAct(); - - renderForYouSection(); - await waitForBatchedUpdatesWithAct(); - - pressFirstBeginButton(); - - expect(mockNavigate).toHaveBeenCalledTimes(1); - expect(mockNavigate).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(reportID)); - }); - }); - }); -}); diff --git a/tests/unit/selectors/TodosTest.ts b/tests/unit/selectors/TodosTest.ts index 7bb2bbeca7e29..2b14df4031334 100644 --- a/tests/unit/selectors/TodosTest.ts +++ b/tests/unit/selectors/TodosTest.ts @@ -1,4 +1,4 @@ -import todosReportCountsSelector, {todosSingleReportIDsSelector} from '@selectors/Todos'; +import todosReportCountsSelector from '@selectors/Todos'; import CONST from '@src/CONST'; import type {TodosDerivedValue} from '@src/types/onyx'; @@ -93,122 +93,3 @@ describe('todosReportCountsSelector', () => { }); }); }); - -describe('todosSingleReportIDsSelector', () => { - it('returns EMPTY_TODOS_SINGLE_REPORT_IDS when todos is undefined', () => { - const result = todosSingleReportIDsSelector(undefined); - - expect(result).toEqual({ - [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: undefined, - [CONST.SEARCH.SEARCH_KEYS.APPROVE]: undefined, - [CONST.SEARCH.SEARCH_KEYS.PAY]: undefined, - [CONST.SEARCH.SEARCH_KEYS.EXPORT]: undefined, - }); - }); - - it('returns EMPTY_TODOS_SINGLE_REPORT_IDS when all arrays are empty', () => { - const todos: TodosDerivedValue = { - reportsToSubmit: [], - reportsToApprove: [], - reportsToPay: [], - reportsToExport: [], - transactionsByReportID: {}, - }; - - const result = todosSingleReportIDsSelector(todos); - - expect(result).toEqual({ - [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: undefined, - [CONST.SEARCH.SEARCH_KEYS.APPROVE]: undefined, - [CONST.SEARCH.SEARCH_KEYS.PAY]: undefined, - [CONST.SEARCH.SEARCH_KEYS.EXPORT]: undefined, - }); - }); - - it('returns report ID when exactly one report exists in each array', () => { - const todos: TodosDerivedValue = { - reportsToSubmit: [{reportID: '1'}] as TodosDerivedValue['reportsToSubmit'], - reportsToApprove: [{reportID: '2'}] as TodosDerivedValue['reportsToApprove'], - reportsToPay: [{reportID: '3'}] as TodosDerivedValue['reportsToPay'], - reportsToExport: [{reportID: '4'}] as TodosDerivedValue['reportsToExport'], - transactionsByReportID: {}, - }; - - const result = todosSingleReportIDsSelector(todos); - - expect(result).toEqual({ - [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: '1', - [CONST.SEARCH.SEARCH_KEYS.APPROVE]: '2', - [CONST.SEARCH.SEARCH_KEYS.PAY]: '3', - [CONST.SEARCH.SEARCH_KEYS.EXPORT]: '4', - }); - }); - - it('returns undefined for arrays with more than one report', () => { - const todos: TodosDerivedValue = { - reportsToSubmit: [{reportID: '1'}, {reportID: '2'}] as TodosDerivedValue['reportsToSubmit'], - reportsToApprove: [{reportID: '3'}, {reportID: '4'}, {reportID: '5'}] as TodosDerivedValue['reportsToApprove'], - reportsToPay: [{reportID: '6'}] as TodosDerivedValue['reportsToPay'], - reportsToExport: [{reportID: '7'}, {reportID: '8'}] as TodosDerivedValue['reportsToExport'], - transactionsByReportID: {}, - }; - - const result = todosSingleReportIDsSelector(todos); - - expect(result).toEqual({ - [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: undefined, - [CONST.SEARCH.SEARCH_KEYS.APPROVE]: undefined, - [CONST.SEARCH.SEARCH_KEYS.PAY]: '6', - [CONST.SEARCH.SEARCH_KEYS.EXPORT]: undefined, - }); - }); - - it('returns the same object reference when called twice with shallowly equal values (memoization)', () => { - const todos: TodosDerivedValue = { - reportsToSubmit: [{reportID: '10'}] as TodosDerivedValue['reportsToSubmit'], - reportsToApprove: [] as unknown as TodosDerivedValue['reportsToApprove'], - reportsToPay: [] as unknown as TodosDerivedValue['reportsToPay'], - reportsToExport: [] as unknown as TodosDerivedValue['reportsToExport'], - transactionsByReportID: {}, - }; - - const first = todosSingleReportIDsSelector(todos); - - const todosClone: TodosDerivedValue = { - reportsToSubmit: [{reportID: '10'}] as TodosDerivedValue['reportsToSubmit'], - reportsToApprove: [] as unknown as TodosDerivedValue['reportsToApprove'], - reportsToPay: [] as unknown as TodosDerivedValue['reportsToPay'], - reportsToExport: [] as unknown as TodosDerivedValue['reportsToExport'], - transactionsByReportID: {}, - }; - - const second = todosSingleReportIDsSelector(todosClone); - - expect(second).toBe(first); - }); - - it('returns a new object reference when values change (memoization invalidation)', () => { - const todos: TodosDerivedValue = { - reportsToSubmit: [{reportID: '20'}] as TodosDerivedValue['reportsToSubmit'], - reportsToApprove: [] as unknown as TodosDerivedValue['reportsToApprove'], - reportsToPay: [] as unknown as TodosDerivedValue['reportsToPay'], - reportsToExport: [] as unknown as TodosDerivedValue['reportsToExport'], - transactionsByReportID: {}, - }; - - const first = todosSingleReportIDsSelector(todos); - - const todosChanged: TodosDerivedValue = { - reportsToSubmit: [{reportID: '21'}] as TodosDerivedValue['reportsToSubmit'], - reportsToApprove: [] as unknown as TodosDerivedValue['reportsToApprove'], - reportsToPay: [] as unknown as TodosDerivedValue['reportsToPay'], - reportsToExport: [] as unknown as TodosDerivedValue['reportsToExport'], - transactionsByReportID: {}, - }; - - const second = todosSingleReportIDsSelector(todosChanged); - - expect(second).not.toBe(first); - expect(second[CONST.SEARCH.SEARCH_KEYS.SUBMIT]).toBe('21'); - }); -});