11import { render , screen , waitFor } from '@testing-library/react' ;
22import userEvent from '@testing-library/user-event' ;
33import { act } from 'react' ;
4- import { describe , expect , it , vi } from 'vitest' ;
4+ import { describe , expect , it , Mock , vi } from 'vitest' ;
55import ReviewDetailsAssessmentStage from './ReviewDetailsAssessmentStage' ;
66import { DOWNLOAD_STAGE } from '../../../../types/generic/downloadStage' ;
77import {
@@ -24,7 +24,7 @@ vi.mock('../../../../helpers/utils/isLocal', () => ({
2424} ) ) ;
2525vi . mock ( 'react-router-dom' , async ( ) => ( {
2626 ...( await vi . importActual ( 'react-router-dom' ) ) ,
27- useNavigate : ( ) : typeof mockedUseNavigate => mockedUseNavigate ,
27+ useNavigate : ( ) : Mock => mockedUseNavigate ,
2828 useParams : ( ) : { reviewId : string } => ( { reviewId : 'test-review-id.v1' } ) ,
2929} ) ) ;
3030
@@ -729,6 +729,155 @@ describe('ReviewDetailsAssessmentPage', () => {
729729 } ) ;
730730 } ) ;
731731
732+ describe ( 'Error handling for file viewing' , ( ) => {
733+ it ( 'navigates to SESSION_EXPIRED when getReviewById returns 403' , async ( ) => {
734+ const user = userEvent . setup ( ) ;
735+ const mockGetReviewById = vi . spyOn ( getReviewsModule , 'getReviewById' ) ;
736+ mockGetReviewById . mockRejectedValue ( { code : '403' } ) ;
737+
738+ render (
739+ < ReviewDetailsAssessmentStage
740+ reviewData = { createMockReviewData ( ) }
741+ setReviewData = { mockSetReviewData }
742+ uploadDocuments = { createMockUploadDocuments ( ) }
743+ downloadStage = { DOWNLOAD_STAGE . SUCCEEDED }
744+ setDownloadStage = { mockSetDownloadStage }
745+ hasExistingRecordInStorage = { true }
746+ /> ,
747+ ) ;
748+
749+ const viewButtons = screen . getAllByRole ( 'button' , { name : / V i e w / i } ) ;
750+ await act ( async ( ) => {
751+ await user . click ( viewButtons [ 1 ] ) ;
752+ } ) ;
753+
754+ await waitFor ( ( ) => {
755+ expect ( mockedUseNavigate ) . toHaveBeenCalledWith ( '/session-expired' ) ;
756+ } ) ;
757+ } ) ;
758+
759+ it ( 'navigates to SERVER_ERROR when getReviewById returns other error' , async ( ) => {
760+ const user = userEvent . setup ( ) ;
761+ const mockGetReviewById = vi . spyOn ( getReviewsModule , 'getReviewById' ) ;
762+ mockGetReviewById . mockRejectedValue ( new Error ( 'Server error' ) ) ;
763+
764+ render (
765+ < ReviewDetailsAssessmentStage
766+ reviewData = { createMockReviewData ( ) }
767+ setReviewData = { mockSetReviewData }
768+ uploadDocuments = { createMockUploadDocuments ( ) }
769+ downloadStage = { DOWNLOAD_STAGE . SUCCEEDED }
770+ setDownloadStage = { mockSetDownloadStage }
771+ hasExistingRecordInStorage = { true }
772+ /> ,
773+ ) ;
774+
775+ const viewButtons = screen . getAllByRole ( 'button' , { name : / V i e w / i } ) ;
776+ await act ( async ( ) => {
777+ await user . click ( viewButtons [ 1 ] ) ;
778+ } ) ;
779+
780+ await waitFor ( ( ) => {
781+ expect ( mockedUseNavigate ) . toHaveBeenCalledWith (
782+ expect . stringContaining ( '/server-error' ) ,
783+ ) ;
784+ } ) ;
785+ } ) ;
786+ } ) ;
787+
788+ describe ( 'Navigation with accept action and multifileReview' , ( ) => {
789+ it ( 'navigates to UPLOAD when accept is selected with single file' , async ( ) => {
790+ const user = userEvent . setup ( ) ;
791+ const singleFileReviewData = createMockReviewData ( false , true , false , '24511000000107' as DOCUMENT_TYPE ) ;
792+ singleFileReviewData . files = [ { fileName : 'single-file.pdf' , uploadDate : '2024-01-15T09:00:00Z' , presignedUrl : 'http://example.com' } ] ;
793+
794+ const singleUploadDoc = [ {
795+ id : 'new-1' ,
796+ file : new File ( [ 'test content' ] , 'single-file.pdf' , { type : 'application/pdf' } ) ,
797+ type : UploadDocumentType . REVIEW ,
798+ state : DOCUMENT_UPLOAD_STATE . SELECTED ,
799+ docType : '24511000000107' as DOCUMENT_TYPE ,
800+ attempts : 0 ,
801+ } ] ;
802+
803+ render (
804+ < ReviewDetailsAssessmentStage
805+ reviewData = { singleFileReviewData }
806+ setReviewData = { mockSetReviewData }
807+ uploadDocuments = { singleUploadDoc }
808+ downloadStage = { DOWNLOAD_STAGE . SUCCEEDED }
809+ setDownloadStage = { mockSetDownloadStage }
810+ hasExistingRecordInStorage = { false }
811+ /> ,
812+ ) ;
813+
814+ const acceptRadio = screen . getByLabelText ( / A c c e p t r e c o r d / i) ;
815+ await user . click ( acceptRadio ) ;
816+
817+ const continueButton = screen . getByRole ( 'button' , { name : 'Continue' } ) ;
818+ await user . click ( continueButton ) ;
819+
820+ await waitFor ( ( ) => {
821+ expect ( mockedUseNavigate ) . toHaveBeenCalledWith (
822+ '/admin/reviews/test-review-id.v1/upload' ,
823+ undefined ,
824+ ) ;
825+ } ) ;
826+ } ) ;
827+
828+ it ( 'navigates to UPLOAD_FILE_ORDER when accept is selected with multiple files' , async ( ) => {
829+ const user = userEvent . setup ( ) ;
830+ const multipleFileReviewData = createMockReviewData ( false , true , false , '24511000000107' as DOCUMENT_TYPE ) ;
831+ multipleFileReviewData . files = [
832+ { fileName : 'file-1.pdf' , uploadDate : '2024-01-15T09:00:00Z' , presignedUrl : 'http://example.com/1' } ,
833+ { fileName : 'file-2.pdf' , uploadDate : '2024-01-16T09:00:00Z' , presignedUrl : 'http://example.com/2' } ,
834+ ] ;
835+
836+ const multiUploadDocs : ReviewUploadDocument [ ] = [
837+ {
838+ id : 'new-1' ,
839+ file : new File ( [ 'test content 1' ] , 'file-1.pdf' , { type : 'application/pdf' } ) ,
840+ type : UploadDocumentType . REVIEW ,
841+ state : DOCUMENT_UPLOAD_STATE . SELECTED ,
842+ docType : '24511000000107' as DOCUMENT_TYPE ,
843+ attempts : 0 ,
844+ } ,
845+ {
846+ id : 'new-2' ,
847+ file : new File ( [ 'test content 2' ] , 'file-2.pdf' , { type : 'application/pdf' } ) ,
848+ type : UploadDocumentType . REVIEW ,
849+ state : DOCUMENT_UPLOAD_STATE . SELECTED ,
850+ docType : '24511000000107' as DOCUMENT_TYPE ,
851+ attempts : 0 ,
852+ } ,
853+ ] ;
854+
855+ render (
856+ < ReviewDetailsAssessmentStage
857+ reviewData = { multipleFileReviewData }
858+ setReviewData = { mockSetReviewData }
859+ uploadDocuments = { multiUploadDocs }
860+ downloadStage = { DOWNLOAD_STAGE . SUCCEEDED }
861+ setDownloadStage = { mockSetDownloadStage }
862+ hasExistingRecordInStorage = { false }
863+ /> ,
864+ ) ;
865+
866+ const acceptRadio = screen . getByLabelText ( / A c c e p t r e c o r d / i) ;
867+ await user . click ( acceptRadio ) ;
868+
869+ const continueButton = screen . getByRole ( 'button' , { name : 'Continue' } ) ;
870+ await user . click ( continueButton ) ;
871+
872+ await waitFor ( ( ) => {
873+ expect ( mockedUseNavigate ) . toHaveBeenCalledWith (
874+ '/admin/reviews/test-review-id.v1/upload-file-order' ,
875+ undefined ,
876+ ) ;
877+ } ) ;
878+ } ) ;
879+ } ) ;
880+
732881 describe ( 'Back button' , ( ) => {
733882 it ( 'renders back button' , ( ) => {
734883 render (
0 commit comments