@@ -509,4 +509,168 @@ export function calculateVariantCountFromSnapshot(snapshot: any, globalConfig?:
509509 }
510510
511511 return variantCount ;
512- }
512+ }
513+
514+ export function startPdfPolling ( ctx : Context ) {
515+ console . log ( chalk . yellow ( '\nFetching PDF test results...' ) ) ;
516+
517+ ctx . log . debug ( `Starting fetching results for build: ${ ctx . build . id || ctx . build . name } ` ) ;
518+ if ( ! ctx . build . id && ! ctx . build . name ) {
519+ ctx . log . error ( chalk . red ( 'Error: Build information not found for fetching results' ) ) ;
520+ return
521+ }
522+
523+ if ( ! ctx . env . LT_USERNAME || ! ctx . env . LT_ACCESS_KEY ) {
524+ console . log ( chalk . red ( 'Error: LT_USERNAME and LT_ACCESS_KEY environment variables are required for fetching results' ) ) ;
525+ return ;
526+ }
527+
528+ let attempts = 0 ;
529+ const maxAttempts = 30 ; // 5 minutes (10 seconds * 30)
530+
531+ console . log ( chalk . yellow ( 'Waiting for results...' ) ) ;
532+
533+ const interval = setInterval ( async ( ) => {
534+ attempts ++ ;
535+
536+ try {
537+ const response = await ctx . client . fetchPdfResults ( ctx , ctx . log ) ;
538+
539+ if ( response . status === 'success' && response . data && response . data . Screenshots ) {
540+ clearInterval ( interval ) ;
541+
542+ const pdfGroups = groupScreenshotsByPdf ( response . data . Screenshots ) ;
543+
544+ const pdfsWithMismatches = countPdfsWithMismatches ( pdfGroups ) ;
545+ const pagesWithMismatches = countPagesWithMismatches ( response . data . Screenshots ) ;
546+
547+ console . log ( chalk . green ( '\n✓ PDF Test Results:' ) ) ;
548+ console . log ( chalk . green ( `Build Name: ${ response . data . buildName } ` ) ) ;
549+ console . log ( chalk . green ( `Project Name: ${ response . data . projectName } ` ) ) ;
550+ console . log ( chalk . green ( `Total PDFs: ${ Object . keys ( pdfGroups ) . length } ` ) ) ;
551+ console . log ( chalk . green ( `Total Pages: ${ response . data . Screenshots . length } ` ) ) ;
552+
553+ if ( pdfsWithMismatches > 0 || pagesWithMismatches > 0 ) {
554+ console . log ( chalk . yellow ( `${ pdfsWithMismatches } PDFs and ${ pagesWithMismatches } Pages in build ${ response . data . buildName } have changes present.` ) ) ;
555+ } else {
556+ console . log ( chalk . green ( 'All PDFs match the baseline.' ) ) ;
557+ }
558+
559+ Object . entries ( pdfGroups ) . forEach ( ( [ pdfName , pages ] ) => {
560+ const hasMismatch = pages . some ( page => page . mismatchPercentage > 0 ) ;
561+ const statusColor = hasMismatch ? chalk . yellow : chalk . green ;
562+
563+ console . log ( statusColor ( `\n📄 ${ pdfName } (${ pages . length } pages)` ) ) ;
564+
565+ pages . forEach ( page => {
566+ const pageStatusColor = page . mismatchPercentage > 0 ? chalk . yellow : chalk . green ;
567+ console . log ( pageStatusColor ( ` - Page ${ getPageNumber ( page . screenshotName ) } : ${ page . status } (Mismatch: ${ page . mismatchPercentage } %)` ) ) ;
568+ } ) ;
569+ } ) ;
570+
571+ const formattedResults = {
572+ status : response . status ,
573+ data : {
574+ buildId : response . data . buildId ,
575+ buildName : response . data . buildName ,
576+ projectName : response . data . projectName ,
577+ buildStatus : response . data . buildStatus ,
578+ pdfs : formatPdfsForOutput ( pdfGroups )
579+ }
580+ } ;
581+
582+ // Save results to file if filename provided
583+ if ( ctx . options . fetchResults && ctx . options . fetchResultsFileName ) {
584+ const filename = ctx . options . fetchResultsFileName !== '' ? ctx . options . fetchResultsFileName : 'pdf-results.json' ;
585+
586+ fs . writeFileSync ( filename , JSON . stringify ( formattedResults , null , 2 ) ) ;
587+ console . log ( chalk . green ( `\nResults saved to ${ filename } ` ) ) ;
588+ }
589+
590+ return ;
591+ } else if ( response . status === 'error' ) {
592+ clearInterval ( interval ) ;
593+ console . log ( chalk . red ( `\nError fetching results: ${ response . message || 'Unknown error' } ` ) ) ;
594+ return ;
595+ } else {
596+ process . stdout . write ( chalk . yellow ( '.' ) ) ;
597+ }
598+
599+ if ( attempts >= maxAttempts ) {
600+ clearInterval ( interval ) ;
601+ console . log ( chalk . red ( '\nTimeout: Could not fetch PDF results after 5 minutes' ) ) ;
602+ return ;
603+ }
604+
605+ } catch ( error : any ) {
606+ ctx . log . debug ( `Error during polling: ${ error . message } ` ) ;
607+
608+ if ( attempts >= maxAttempts ) {
609+ clearInterval ( interval ) ;
610+ console . log ( chalk . red ( '\nTimeout: Could not fetch PDF results after 5 minutes' ) ) ;
611+ if ( error . response && error . response . data ) {
612+ console . log ( chalk . red ( `Error details: ${ JSON . stringify ( error . response . data ) } ` ) ) ;
613+ } else {
614+ console . log ( chalk . red ( `Error details: ${ error . message } ` ) ) ;
615+ }
616+ return ;
617+ }
618+ process . stdout . write ( chalk . yellow ( '.' ) ) ;
619+ }
620+ } , 10000 ) ;
621+ }
622+
623+ function groupScreenshotsByPdf ( screenshots : any [ ] ) : Record < string , any [ ] > {
624+ const pdfGroups : Record < string , any [ ] > = { } ;
625+
626+ screenshots . forEach ( screenshot => {
627+ // screenshot name format: "pdf-name.pdf#page-number"
628+ const pdfName = screenshot . screenshotName . split ( '#' ) [ 0 ] ;
629+
630+ if ( ! pdfGroups [ pdfName ] ) {
631+ pdfGroups [ pdfName ] = [ ] ;
632+ }
633+
634+ pdfGroups [ pdfName ] . push ( screenshot ) ;
635+ } ) ;
636+
637+ return pdfGroups ;
638+ }
639+
640+ function countPdfsWithMismatches ( pdfGroups : Record < string , any [ ] > ) : number {
641+ let count = 0 ;
642+
643+ Object . values ( pdfGroups ) . forEach ( pages => {
644+ if ( pages . some ( page => page . mismatchPercentage > 0 ) ) {
645+ count ++ ;
646+ }
647+ } ) ;
648+
649+ return count ;
650+ }
651+
652+ function countPagesWithMismatches ( screenshots : any [ ] ) : number {
653+ return screenshots . filter ( screenshot => screenshot . mismatchPercentage > 0 ) . length ;
654+ }
655+
656+ function formatPdfsForOutput ( pdfGroups : Record < string , any [ ] > ) : any [ ] {
657+ return Object . entries ( pdfGroups ) . map ( ( [ pdfName , pages ] ) => {
658+ return {
659+ pdfName,
660+ pageCount : pages . length ,
661+ pages : pages . map ( page => ( {
662+ pageNumber : getPageNumber ( page . screenshotName ) ,
663+ screenshotId : page . screenshotId ,
664+ mismatchPercentage : page . mismatchPercentage ,
665+ threshold : page . threshold ,
666+ status : page . status ,
667+ screenshotUrl : page . screenshotUrl
668+ } ) )
669+ } ;
670+ } ) ;
671+ }
672+
673+ function getPageNumber ( screenshotName : string ) : string {
674+ const parts = screenshotName . split ( '#' ) ;
675+ return parts . length > 1 ? parts [ 1 ] : '1' ;
676+ }
0 commit comments