11"""BIAB Page object for automating interactions with the Multi-Agent Planner UI."""
22
33import logging
4+ import os
5+ from datetime import datetime
46from playwright .sync_api import expect
57from base .base import BasePage
68
@@ -365,8 +367,6 @@ def approve_retail_task_plan(self):
365367 # No clarification input detected, proceed normally
366368 logger .info (f"✓ No clarification input detected - proceeding normally: { e } " )
367369 return False
368-
369- logger .info ("Task plan approval and processing completed successfully!" )
370370
371371 def approve_task_plan (self ):
372372 """Approve the task plan and wait for processing to complete (without clarification check)."""
@@ -475,8 +475,6 @@ def approve_rfp_task_plan(self):
475475 # No clarification input detected, proceed normally
476476 logger .info (f"✓ No clarification input detected - proceeding normally: { e } " )
477477 return False
478-
479- logger .info ("RFP task plan approval and processing completed successfully!" )
480478
481479 def approve_contract_compliance_task_plan (self ):
482480 """Approve the Contract Compliance task plan and wait for processing to complete."""
@@ -509,8 +507,7 @@ def approve_contract_compliance_task_plan(self):
509507 # No clarification input detected, proceed normally
510508 logger .info (f"✓ No clarification input detected - proceeding normally: { e } " )
511509 return False
512-
513- logger .info ("Contract Compliance task plan approval and processing completed successfully!" )
510+
514511 def validate_retail_customer_response (self ):
515512 """Validate the retail customer response."""
516513
@@ -718,27 +715,30 @@ def validate_rfp_response(self):
718715 expect (self .page .locator (self .RFP_RESPONSE_VALIDATION )).to_be_visible (timeout = 60000 )
719716 logger .info ("✓ RFP response is visible" )
720717
721- # Soft assertions for RFP Summary, RFP Risk, and RFP Compliance
722- logger .info ("Checking RFP Summary visibility..." )
723- try :
724- expect (self .page .locator (self .RFP_SUMMARY ).first ).to_be_visible (timeout = 10000 )
725- logger .info ("✓ RFP Summary is visible" )
726- except (AssertionError , TimeoutError ) as e :
727- logger .warning (f"⚠ RFP Summary Agent is NOT Utilized in response: { e } " )
728-
729- logger .info ("Checking RFP Risk visibility..." )
730- try :
731- expect (self .page .locator (self .RFP_RISK ).first ).to_be_visible (timeout = 10000 )
732- logger .info ("✓ RFP Risk is visible" )
733- except (AssertionError , TimeoutError ) as e :
734- logger .warning (f"⚠ RFP Risk Agent is NOT Utilized in response: { e } " )
735-
736- logger .info ("Checking RFP Compliance visibility..." )
718+ # Validate RFP response contains expected content
719+ logger .info ("Checking for RFP analysis content..." )
737720 try :
738- expect (self .page .locator (self .RFP_COMPLIANCE ).first ).to_be_visible (timeout = 10000 )
739- logger .info ("✓ RFP Compliance is visible" )
740- except (AssertionError , TimeoutError ) as e :
741- logger .warning (f"⚠ RFP Compliance Agent is NOT Utilized in response: { e } " )
721+ # Look for common RFP response content patterns
722+ rfp_content_patterns = [
723+ "//p[contains(text(), 'RFP')]" ,
724+ "//p[contains(text(), 'proposal')]" ,
725+ "//p[contains(text(), 'Woodgrove Bank')]" ,
726+ "//p[contains(text(), 'Contoso')]" ,
727+ "//p[contains(text(), 'response')]" ,
728+ "//p[contains(text(), 'project')]"
729+ ]
730+
731+ content_found = False
732+ for pattern in rfp_content_patterns :
733+ if self .page .locator (pattern ).first .is_visible (timeout = 5000 ):
734+ logger .info (f"✓ RFP response content validated with pattern" )
735+ content_found = True
736+ break
737+
738+ if not content_found :
739+ logger .warning ("⚠ No specific RFP content patterns found, but main response is visible" )
740+ except Exception as e :
741+ logger .warning (f"⚠ RFP content validation check failed, but main response is successful: { e } " )
742742
743743 def validate_contract_compliance_response (self ):
744744 """Validate the Contract Compliance response."""
@@ -760,27 +760,30 @@ def validate_contract_compliance_response(self):
760760 expect (self .page .locator (self .CC_RESPONSE_VALIDATION )).to_be_visible (timeout = 60000 )
761761 logger .info ("✓ Contract Compliance response is visible" )
762762
763- # Soft assertions for Contract Summary, Contract Risk, and Contract Compliance
764- logger .info ("Checking Contract Summary visibility..." )
765- try :
766- expect (self .page .locator (self .CONTRACT_SUMMARY ).first ).to_be_visible (timeout = 10000 )
767- logger .info ("✓ Contract Summary is visible" )
768- except (AssertionError , TimeoutError ) as e :
769- logger .warning (f"⚠ Contract Summary Agent is NOT Utilized in response: { e } " )
770-
771- logger .info ("Checking Contract Risk visibility..." )
763+ # Validate Contract Compliance response contains expected content
764+ logger .info ("Checking for Contract Compliance analysis content..." )
772765 try :
773- expect (self .page .locator (self .CONTRACT_RISK ).first ).to_be_visible (timeout = 10000 )
774- logger .info ("✓ Contract Risk is visible" )
775- except (AssertionError , TimeoutError ) as e :
776- logger .warning (f"⚠ Contract Risk Agent is NOT Utilized in response: { e } " )
777-
778- logger .info ("Checking Contract Compliance visibility..." )
779- try :
780- expect (self .page .locator (self .CONTRACT_COMPLIANCE ).first ).to_be_visible (timeout = 10000 )
781- logger .info ("✓ Contract Compliance is visible" )
782- except (AssertionError , TimeoutError ) as e :
783- logger .warning (f"⚠ Contract Compliance Agent is NOT Utilized in response: { e } " )
766+ # Look for common contract compliance response content patterns
767+ cc_content_patterns = [
768+ "//p[contains(text(), 'contract')]" ,
769+ "//p[contains(text(), 'compliance')]" ,
770+ "//p[contains(text(), 'agreement')]" ,
771+ "//p[contains(text(), 'terms')]" ,
772+ "//p[contains(text(), 'review')]" ,
773+ "//h5[contains(text(), 'Contract')]"
774+ ]
775+
776+ content_found = False
777+ for pattern in cc_content_patterns :
778+ if self .page .locator (pattern ).first .is_visible (timeout = 5000 ):
779+ logger .info (f"✓ Contract Compliance response content validated with pattern" )
780+ content_found = True
781+ break
782+
783+ if not content_found :
784+ logger .warning ("⚠ No specific Contract Compliance content patterns found, but main response is visible" )
785+ except Exception as e :
786+ logger .warning (f"⚠ Contract Compliance content validation check failed, but main response is successful: { e } " )
784787
785788 def click_new_task (self ):
786789 """Click on the New Task button."""
@@ -805,13 +808,21 @@ def input_clarification_and_send(self, clarification_text):
805808
806809 logger .info ("Clarification input and send completed successfully!" )
807810
811+ # Try to wait for processing message, but if it's already gone (fast processing), that's okay
808812 logger .info ("Waiting for 'Processing your plan' message to be visible..." )
809- expect (self .page .locator (self .PROCESSING_PLAN )).to_be_visible (timeout = 15000 )
810- logger .info ("✓ 'Processing your plan' message is visible" )
811-
812- logger .info ("Waiting for plan processing to complete..." )
813- self .page .locator (self .PROCESSING_PLAN ).wait_for (state = "hidden" , timeout = 200000 )
814- logger .info ("✓ Plan processing completed" )
813+ try :
814+ expect (self .page .locator (self .PROCESSING_PLAN )).to_be_visible (timeout = 10000 )
815+ logger .info ("✓ 'Processing your plan' message is visible" )
816+
817+ logger .info ("Waiting for plan processing to complete..." )
818+ self .page .locator (self .PROCESSING_PLAN ).wait_for (state = "hidden" , timeout = 200000 )
819+ logger .info ("✓ Plan processing completed" )
820+ except Exception as e :
821+ # Processing may have completed so quickly that the message was never detected
822+ logger .info (f"Processing message not detected or already completed: { e } " )
823+ # Give a small buffer to ensure any processing is complete
824+ self .page .wait_for_timeout (3000 )
825+ logger .info ("✓ Proceeding - processing likely completed quickly" )
815826
816827 def input_rai_clarification_and_send (self , clarification_text ):
817828 """Input RAI clarification text and click send button (for RAI testing)."""
@@ -873,7 +884,7 @@ def validate_rai_error_message(self):
873884 logger .info (f"✓ RAI error message found with locator: { locator } " )
874885 error_found = True
875886 break
876- except :
887+ except Exception :
877888 continue
878889
879890 if not error_found :
@@ -882,17 +893,25 @@ def validate_rai_error_message(self):
882893 if not self .page .locator (self .CREATING_PLAN ).is_visible (timeout = 2000 ):
883894 logger .warning ("⚠ No explicit error message, but plan creation didn't start - input may have been silently rejected or truncated" )
884895 error_found = True
885- except :
886- pass
896+ except Exception as e :
897+ # Ignore failures in this secondary check, but log for troubleshooting
898+ logger .debug ("Failed to verify CREATING_PLAN visibility while checking for RAI rejection state: %s" , e )
887899
888900 if not error_found :
889- logger .warning ( "⚠ No RAI error message found, but this may be expected if input was accepted or handled differently " )
890- # Take a screenshot for investigation
901+ logger .error ( "✗ No RAI error or rejection state detected; prompt appears to have been accepted unexpectedly " )
902+ # Take a screenshot for investigation before failing the test
891903 try :
892- screenshot = self .page .screenshot ()
893- logger .info ("Screenshot captured for investigation" )
894- except :
895- pass
904+ timestamp = datetime .now ().strftime ("%Y%m%d_%H%M%S" )
905+ screenshots_dir = os .path .join (os .path .dirname (__file__ ), ".." , "tests" , "screenshots" )
906+ os .makedirs (screenshots_dir , exist_ok = True )
907+ screenshot_path = os .path .join (screenshots_dir , f"rai_validation_failed_{ timestamp } .png" )
908+ self .page .screenshot (path = screenshot_path )
909+ logger .info (f"Screenshot captured for investigation: { screenshot_path } " )
910+ except Exception as e :
911+ logger .warning ("Failed to capture screenshot when RAI validation failed: %s" , e )
912+ raise AssertionError (
913+ "Expected RAI to block the prompt, but no error message or rejection state was detected."
914+ )
896915
897916 def validate_rai_clarification_error_message (self ):
898917 """Validate that the RAI 'Failed to submit clarification' error message is visible."""
0 commit comments