11/* eslint-disable @typescript-eslint/naming-convention */
22import { act , renderHook } from '@testing-library/react-native' ;
3- import type { OnyxCollection , OnyxEntry } from 'react-native-onyx' ;
3+ import type { OnyxCollection , OnyxEntry , OnyxMultiSetInput } from 'react-native-onyx' ;
44import Onyx from 'react-native-onyx' ;
55import useReportIsArchived from '@hooks/useReportIsArchived' ;
66import DateUtils from '@libs/DateUtils' ;
77import { getLastActorDisplayName } from '@libs/OptionsListUtils' ;
88// eslint-disable-next-line no-restricted-syntax
99import type * as PolicyUtils from '@libs/PolicyUtils' ;
1010import { getOriginalMessage , getReportActionMessageText } from '@libs/ReportActionsUtils' ;
11- import { formatReportLastMessageText , getAllReportErrors , getReportPreviewMessage } from '@libs/ReportUtils' ;
11+ import {
12+ formatReportLastMessageText ,
13+ generateReportID ,
14+ getAllReportErrors ,
15+ getReasonAndReportActionThatRequiresAttention ,
16+ getReportPreviewMessage ,
17+ } from '@libs/ReportUtils' ;
1218import SidebarUtils from '@libs/SidebarUtils' ;
1319import initOnyxDerivedValues from '@userActions/OnyxDerived' ;
1420import CONST from '@src/CONST' ;
@@ -22,11 +28,13 @@ import {chatReportR14932, iouReportR14932} from '../../__mocks__/reportData/repo
2228import createRandomPolicy from '../utils/collections/policies' ;
2329import createRandomReportAction from '../utils/collections/reportActions' ;
2430import { createRandomReport } from '../utils/collections/reports' ;
31+ import createRandomTransaction from '../utils/collections/transaction' ;
2532import { createSidebarReportsCollection , createSidebarTestData } from '../utils/collections/sidebarReports' ;
2633import * as LHNTestUtils from '../utils/LHNTestUtils' ;
2734import { localeCompare } from '../utils/TestHelper' ;
2835import waitForBatchedUpdates from '../utils/waitForBatchedUpdates' ;
2936import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct' ;
37+ import { generateTransactionID } from '@libs/actions/Transaction' ;
3038
3139// Mock PolicyUtils
3240jest . mock ( '@libs/PolicyUtils' , ( ) => ( {
@@ -573,6 +581,115 @@ describe('SidebarUtils', () => {
573581 expect ( result ) . toBe ( true ) ;
574582 } ) ;
575583
584+ it ( 'returns true when submitter has held expenses even if outstanding tasks trigger GBR' , async ( ) => {
585+ const policyID = generateReportID ( ) ;
586+ const expenseChatID = generateReportID ( ) ;
587+ const expenseReportID = generateReportID ( ) ;
588+ const holdReportActionID = generateReportID ( ) ;
589+ const delegateEmail = 'copilot@example.com' ;
590+
591+ const policyExpenseChat : Report = {
592+ reportID : expenseChatID ,
593+ chatType : CONST . REPORT . CHAT_TYPE . POLICY_EXPENSE_CHAT ,
594+ type : CONST . REPORT . TYPE . CHAT ,
595+ ownerAccountID : 12345 ,
596+ policyID,
597+ hasOutstandingChildRequest : true ,
598+ stateNum : CONST . REPORT . STATE_NUM . OPEN ,
599+ statusNum : CONST . REPORT . STATUS_NUM . OPEN ,
600+ } ;
601+
602+ const expenseReport : Report = {
603+ reportID : expenseReportID ,
604+ chatReportID : expenseChatID ,
605+ type : CONST . REPORT . TYPE . EXPENSE ,
606+ ownerAccountID : 12345 ,
607+ managerID : 12345 ,
608+ policyID,
609+ stateNum : CONST . REPORT . STATE_NUM . OPEN ,
610+ statusNum : CONST . REPORT . STATUS_NUM . OPEN ,
611+ } ;
612+
613+ const baseTransaction = createRandomTransaction ( 700 ) ;
614+ const transactionID = generateTransactionID ( ) ;
615+ const transaction : Transaction = {
616+ ...baseTransaction ,
617+ transactionID,
618+ reportID : expenseReport . reportID ,
619+ amount : 12345 ,
620+ currency : CONST . CURRENCY . USD ,
621+ status : CONST . TRANSACTION . STATUS . POSTED ,
622+ comment : {
623+ ...( baseTransaction . comment ?? { } ) ,
624+ hold : holdReportActionID ,
625+ } ,
626+ } ;
627+
628+ const transactionKey = `${ ONYXKEYS . COLLECTION . TRANSACTION } ${ transactionID } ` as const ;
629+ const transactionViolationsKey = `${ ONYXKEYS . COLLECTION . TRANSACTION_VIOLATIONS } ${ transactionID } ` as const ;
630+ const transactionViolations : OnyxCollection < TransactionViolation [ ] > = {
631+ [ transactionViolationsKey ] : [
632+ {
633+ name : CONST . VIOLATIONS . HOLD ,
634+ type : CONST . VIOLATION_TYPES . VIOLATION ,
635+ showInReview : true ,
636+ } ,
637+ ] ,
638+ } ;
639+
640+ await act ( async ( ) => {
641+ await Onyx . multiSet ( {
642+ [ ONYXKEYS . SESSION ] : {
643+ accountID : 12345 ,
644+ email : delegateEmail ,
645+ } ,
646+ [ ONYXKEYS . ACCOUNT ] : {
647+ delegatedAccess : {
648+ delegate : delegateEmail ,
649+ delegates : [ { email : delegateEmail , role : CONST . DELEGATE_ROLE . ALL } ] ,
650+ } ,
651+ } ,
652+ [ `${ ONYXKEYS . COLLECTION . REPORT } ${ policyExpenseChat . reportID } ` ] : policyExpenseChat ,
653+ [ `${ ONYXKEYS . COLLECTION . REPORT } ${ expenseReport . reportID } ` ] : expenseReport ,
654+ [ transactionKey ] : transaction ,
655+ [ transactionViolationsKey ] : transactionViolations [ transactionViolationsKey ] ,
656+ } as unknown as OnyxMultiSetInput ) ;
657+ } ) ;
658+
659+ await waitForBatchedUpdatesWithAct ( ) ;
660+
661+ const requiresAttention = getReasonAndReportActionThatRequiresAttention ( policyExpenseChat ) ;
662+ expect ( requiresAttention ?. reason ) . toBe ( CONST . REQUIRES_ATTENTION_REASONS . HAS_CHILD_REPORT_AWAITING_ACTION ) ;
663+
664+ const { reason} =
665+ SidebarUtils . getReasonAndReportActionThatHasRedBrickRoad (
666+ policyExpenseChat ,
667+ policyExpenseChat ,
668+ { } as OnyxEntry < ReportActions > ,
669+ true ,
670+ { } ,
671+ { [ transactionKey ] : transaction } ,
672+ transactionViolations ,
673+ false ,
674+ ) ?? { } ;
675+
676+ expect ( reason ) . toBe ( CONST . RBR_REASONS . HAS_TRANSACTION_THREAD_VIOLATIONS ) ;
677+
678+ const { result : isReportArchived } = renderHook ( ( ) => useReportIsArchived ( policyExpenseChat . reportID ) ) ;
679+ const hasRedBrickRoad = SidebarUtils . shouldShowRedBrickRoad (
680+ policyExpenseChat ,
681+ policyExpenseChat ,
682+ { } as OnyxEntry < ReportActions > ,
683+ true ,
684+ { } ,
685+ { [ transactionKey ] : transaction } ,
686+ transactionViolations as OnyxCollection < TransactionViolations > ,
687+ isReportArchived . current ,
688+ ) ;
689+
690+ expect ( hasRedBrickRoad ) . toBe ( true ) ;
691+ } ) ;
692+
576693 it ( 'returns true when report has errors' , ( ) => {
577694 const MOCK_REPORT : Report = {
578695 reportID : '1' ,
0 commit comments