@@ -477,6 +477,146 @@ describe('Model transfer jobs', () => {
477477 } ) ;
478478 } ) ;
479479
480+ it ( 'should show truncated error message below Failed label when errorMessage exists' , ( ) => {
481+ interceptWithSingleFailedJob (
482+ 'job-with-error' ,
483+ 'Connection timeout while uploading to destination bucket' ,
484+ ) ;
485+
486+ modelTransferJobsPage . visit ( modelRegistryName ) ;
487+ modelTransferJobsPage . findTableRows ( ) . should ( 'have.length' , 1 ) ;
488+
489+ const row = modelTransferJobsPage . getRow ( 'job-with-error' ) ;
490+ row . findStatus ( ) . should ( 'contain.text' , 'Failed' ) ;
491+ row
492+ . findErrorMessage ( )
493+ . should ( 'be.visible' )
494+ . and ( 'contain.text' , 'Connection timeout while uploading to destination bucket' ) ;
495+ } ) ;
496+
497+ it ( 'should not show error message when job is Failed but errorMessage is undefined' , ( ) => {
498+ const failedJobList = mockModelTransferJobList ( {
499+ items : [
500+ mockModelTransferJob ( {
501+ id : 'job-failed-no-msg' ,
502+ name : 'job-failed-no-msg' ,
503+ jobDisplayName : 'job-failed-no-msg' ,
504+ status : ModelTransferJobStatus . FAILED ,
505+ errorMessage : undefined ,
506+ } ) ,
507+ ] ,
508+ size : 1 ,
509+ pageSize : 10 ,
510+ nextPageToken : '' ,
511+ } ) ;
512+
513+ cy . intercept (
514+ 'GET' ,
515+ `**/api/${ MODEL_REGISTRY_API_VERSION } /model_registry/${ modelRegistryName } /model_transfer_jobs*` ,
516+ mockModArchResponse ( failedJobList ) ,
517+ ) ;
518+
519+ modelTransferJobsPage . visit ( modelRegistryName ) ;
520+
521+ const row = modelTransferJobsPage . getRow ( 'job-failed-no-msg' ) ;
522+ row . findStatus ( ) . should ( 'contain.text' , 'Failed' ) ;
523+ row . findErrorMessage ( ) . should ( 'not.exist' ) ;
524+ } ) ;
525+
526+ it ( 'should not show error message when errorMessage is an empty string' , ( ) => {
527+ const failedJobList = mockModelTransferJobList ( {
528+ items : [
529+ mockModelTransferJob ( {
530+ id : 'job-failed-empty-msg' ,
531+ name : 'job-failed-empty-msg' ,
532+ jobDisplayName : 'job-failed-empty-msg' ,
533+ status : ModelTransferJobStatus . FAILED ,
534+ errorMessage : '' ,
535+ } ) ,
536+ ] ,
537+ size : 1 ,
538+ pageSize : 10 ,
539+ nextPageToken : '' ,
540+ } ) ;
541+
542+ cy . intercept (
543+ 'GET' ,
544+ `**/api/${ MODEL_REGISTRY_API_VERSION } /model_registry/${ modelRegistryName } /model_transfer_jobs*` ,
545+ mockModArchResponse ( failedJobList ) ,
546+ ) ;
547+
548+ modelTransferJobsPage . visit ( modelRegistryName ) ;
549+
550+ const row = modelTransferJobsPage . getRow ( 'job-failed-empty-msg' ) ;
551+ row . findStatus ( ) . should ( 'contain.text' , 'Failed' ) ;
552+ row . findErrorMessage ( ) . should ( 'not.exist' ) ;
553+ } ) ;
554+
555+ it ( 'should open status modal when clicking the truncated error message' , ( ) => {
556+ interceptWithSingleFailedJob ( 'job-click-error' , 'Upload failed: insufficient storage' ) ;
557+
558+ cy . intercept ( 'GET' , '**/model_transfer_jobs/job-click-error/events*' , {
559+ forceNetworkError : true ,
560+ } ) ;
561+
562+ modelTransferJobsPage . visit ( modelRegistryName ) ;
563+
564+ const row = modelTransferJobsPage . getRow ( 'job-click-error' ) ;
565+ row . findErrorMessage ( ) . click ( ) ;
566+
567+ cy . findByTestId ( 'transfer-job-status-modal' ) . should ( 'be.visible' ) ;
568+ cy . findByLabelText ( 'Close' ) . click ( ) ;
569+ cy . findByTestId ( 'transfer-job-status-modal' ) . should ( 'not.exist' ) ;
570+ } ) ;
571+
572+ it ( 'should show retry button for failed jobs and open retry modal on click' , ( ) => {
573+ interceptWithSingleFailedJob ( 'job-retry-test' , 'Connection error' ) ;
574+
575+ cy . intercept (
576+ 'PUT' ,
577+ `**/api/${ MODEL_REGISTRY_API_VERSION } /model_registry/${ modelRegistryName } /model_transfer_jobs/job-retry-test*` ,
578+ { statusCode : 200 , body : { } } ,
579+ ) . as ( 'retryJob' ) ;
580+
581+ modelTransferJobsPage . visit ( modelRegistryName ) ;
582+
583+ const row = modelTransferJobsPage . getRow ( 'job-retry-test' ) ;
584+ row . findRetryButton ( ) . should ( 'be.visible' ) . click ( ) ;
585+
586+ modelTransferJobsPage . findRetryModal ( ) . should ( 'be.visible' ) ;
587+ modelTransferJobsPage . findRetryModal ( ) . contains ( 'Retry model transfer job?' ) . should ( 'exist' ) ;
588+ modelTransferJobsPage . findRetryModalSubmitButton ( ) . should ( 'be.visible' ) ;
589+ } ) ;
590+
591+ it ( 'should not show error message for non-FAILED statuses' , ( ) => {
592+ const completedJobList = mockModelTransferJobList ( {
593+ items : [
594+ mockModelTransferJob ( {
595+ id : 'job-completed-no-error' ,
596+ name : 'job-completed-no-error' ,
597+ jobDisplayName : 'job-completed-no-error' ,
598+ status : ModelTransferJobStatus . COMPLETED ,
599+ } ) ,
600+ ] ,
601+ size : 1 ,
602+ pageSize : 10 ,
603+ nextPageToken : '' ,
604+ } ) ;
605+
606+ cy . intercept (
607+ 'GET' ,
608+ `**/api/${ MODEL_REGISTRY_API_VERSION } /model_registry/${ modelRegistryName } /model_transfer_jobs*` ,
609+ mockModArchResponse ( completedJobList ) ,
610+ ) ;
611+
612+ modelTransferJobsPage . visit ( modelRegistryName ) ;
613+
614+ const row = modelTransferJobsPage . getRow ( 'job-completed-no-error' ) ;
615+ row . findStatus ( ) . should ( 'contain.text' , 'Complete' ) ;
616+ row . findErrorMessage ( ) . should ( 'not.exist' ) ;
617+ row . findRetryButton ( ) . should ( 'not.exist' ) ;
618+ } ) ;
619+
480620 it ( 'should show the empty state when there are no transfer jobs' , ( ) => {
481621 const emptyList = mockModelTransferJobList ( {
482622 items : [ ] ,
0 commit comments