11from  base .base  import  BasePage 
22from  pytest_check  import  check 
3+ from  config .constants  import  * 
4+ import  logging 
5+ logger  =  logging .getLogger (__name__ )
36import  time 
4- from  collections  import  defaultdict 
57
68
79class  DraftPage (BasePage ):
8-     # Principal_Amount_and_Date = "div:nth-child(3) div:nth-child(2) span:nth-child(1) textarea:nth-child(1)" 
9-     # Borrower_Information = "div:nth-child(3) div:nth-child(2) span:nth-child(1) textarea:nth-child(1)" 
10-     # Payee_Information = "//div[3]//div[2]//span[1]//textarea[1]" 
1110    Draft_Sections  =  "//textarea" 
1211    Draft_headings  =  "//span[@class='fui-Text ___nl2uoq0 fk6fouc f4ybsrx f1i3iumi f16wzh4i fpgzoln f1w7gpdv f6juhto f1gl81tg f2jf649 fepr9ql febqm8h']" 
1312    invalid_response  =  "The requested information is not available in the retrieved data. Please try another query or topic." 
1413    invalid_response1  =  "There was an issue fetching your data. Please try again." 
15-     invalid_response2   =   " " 
14+     
1615
1716    def  __init__ (self , page ):
1817        self .page  =  page 
1918
20-     def  check_draft_sections (self , timeout : float  =  180.0 , poll_interval : float  =  0.5 ):
21-         """ 
22-         Waits for all <textarea> draft sections to load valid content using .input_value(). 
23-         Scrolls into view if needed, retries until timeout. 
24-         Raises clear errors if validation fails. 
25-         """ 
26-         from  collections  import  defaultdict 
27-         import  time 
28-         start_time  =  time .time ()
19+     def  validate_draft_sections_loaded (self ):
20+         max_wait_time  =  180   # seconds 
21+         poll_interval  =  2 
2922
23+         self .page .wait_for_timeout (25000 )
3024
31-         while   time . time ()  -   start_time   <   timeout : 
32-              section_elements   =  self .page .locator (self . Draft_Sections )
33-              heading_elements   =   self . page . locator ( self . Draft_headings )
25+         # All draft section containers 
26+         section_blocks   =  self .page .locator ("//div[@class='ms-Stack ___mit7380 f4zyqsv f6m9rw3 fwbpcpn folxr9a f1s274it css-103']" )
27+         total_sections   =   section_blocks . count ( )
3428
35-             section_count  =  section_elements .count ()
36-             heading_count  =  heading_elements .count ()
29+         logger .info (f"🔍 Total sections found: { total_sections }  " )
3730
38-             if  section_count  <  13  or  heading_count  <  13 :
39-                 print ("[WAIT] Waiting for all sections to appear..." )
40-                 time .sleep (poll_interval )
41-                 continue 
31+         for  index  in  range (total_sections ):
32+             section  =  section_blocks .nth (index )
4233
43-             failed_sections  =  defaultdict (str )
34+             try :
35+                 section .scroll_into_view_if_needed ()
36+                 self .page .wait_for_timeout (500 )
4437
45-             for  i  in  range (section_count ):
46-                 section  =  section_elements .nth (i )
38+                 title_element  =  section .locator ("//span[@class='fui-Text ___nl2uoq0 fk6fouc f4ybsrx f1i3iumi f16wzh4i fpgzoln f1w7gpdv f6juhto f1gl81tg f2jf649 fepr9ql febqm8h']" )
39+                 title_text  =  title_element .inner_text (timeout = 5000 ).strip ()
40+             except  Exception  as  e :
41+                 logger .error (f"❌ Could not read title for section #{ index  +  1 }  : { e }  " )
42+                 continue 
4743
44+             logger .info (f"➡️ Validating section [{ index  +  1 }  /{ total_sections }  ]: '{ title_text }  '" )
45+ 
46+             content_locator  =  section .locator ("//textarea" )
47+             generate_btn  =  section .locator ("//span[@class='fui-Button__icon rywnvv2 ___963sj20 f1nizpg2']" )
48+             spinner_locator  =  section .locator ("//div[@id='section-card-spinner']" )
49+ 
50+             content_loaded  =  False 
51+ 
52+             # 🚨 If spinner is visible inside this section, click generate immediately 
53+             try :
54+                 if  spinner_locator .is_visible (timeout = 1000 ):
55+                     logger .warning (f"⏳ Spinner found in section '{ title_text }  '. Clicking Generate immediately." )
56+                     generate_btn .click ()
57+                     self .page .wait_for_timeout (3000 )
58+                     confirm_btn  =  self .page .locator ("//button[@class='fui-Button r1alrhcs ___zqkcn80 fd1o0ie fjxutwb fwiml72 fj8njcf fzcpov4 f1d2rq10 f1mk8lai ff3glw6']" )
59+                     if  confirm_btn .is_visible (timeout = 3000 ):
60+                         confirm_btn .click ()
61+                         logger .info (f"🟢 Clicked Confirm button for section '{ title_text }  '" )
62+                     else :
63+                         logger .warning (f"⚠️ Confirm button not visible for section '{ title_text }  '" )
64+             except  Exception  as  e :
65+                 logger .error (f"❌ Error while clicking Confirm button for section '{ title_text }  ': { e }  " )
66+ 
67+             # ⏳ Retry short wait (15s) for content to load 
68+             short_wait  =  15 
69+             short_start  =  time .time ()
70+             while  time .time () -  short_start  <  short_wait :
4871                try :
49-                     # Scroll into view and wait a bit for rendering 
50-                     section .scroll_into_view_if_needed (timeout = 2000 )
51-                     self .page .wait_for_timeout (200 )
52- 
53-                     # Extract content from <textarea> 
54-                     section_text  =  section .input_value ().strip ()
55- 
56-                     if  not  section_text :
57-                         failed_sections [i ] =  "Empty" 
58-                     elif  section_text  in  (self .invalid_response , self .invalid_response1 ):
59-                         failed_sections [i ] =  f"Invalid: { repr (section_text [:30 ])}  " 
60- 
61-                 except  Exception  as  e :
62-                     failed_sections [i ] =  f"Exception: { str (e )}  " 
63- 
64-             if  not  failed_sections :
65-                 break   # ✅ All good 
66-             else :
67-                 print (f"[WAITING] Sections not ready yet: { failed_sections }  " )
72+                     content  =  content_locator .text_content (timeout = 2000 ).strip ()
73+                     if  content :
74+                         logger .info (f"✅ Section '{ title_text }  ' loaded after Generate + Confirm." )
75+                         content_loaded  =  True 
76+                         break 
77+                 except :
78+                     pass 
79+                 time .sleep (1 )
80+ 
81+             if  not  content_loaded :
82+                 logger .error (f"❌ Section '{ title_text }  ' still empty after Generate + Confirm wait ({ short_wait }  s). Skipping." )
83+ 
84+             # Step 1: Wait for content to load normally 
85+             start  =  time .time ()
86+             while  time .time () -  start  <  max_wait_time :
87+                 try :
88+                     content  =  content_locator .text_content (timeout = 2000 ).strip ()
89+                     if  content :
90+                         logger .info (f"✅ Section '{ title_text }  ' loaded successfully." )
91+                         content_loaded  =  True 
92+                         break 
93+                 except :
94+                     pass 
6895                time .sleep (poll_interval )
6996
70-         else :
71-             raise  TimeoutError (f"❌ Timeout: These sections did not load valid content: { failed_sections }  " )
72- 
73-         # ✅ Final validations after loading 
74-         for  i  in  range (section_count ):
75-             section  =  section_elements .nth (i )
76-             heading  =  heading_elements .nth (i )
77- 
78-             section .scroll_into_view_if_needed (timeout = 2000 )
79-             self .page .wait_for_timeout (200 )
80- 
81-             heading_text  =  heading .inner_text (timeout = 3000 ).strip ()
82-             content  =  section .input_value ().strip ()
97+             # Step 2: If still not loaded, click Generate and retry 
98+             if  not  content_loaded :
99+                 logger .warning (f"⚠️ Section '{ title_text }  ' is empty. Attempting 'Generate'..." )
83100
84-             print (f"[VALIDATING] Section { i }  : '{ heading_text }  ' → { repr (content [:60 ])}  ..." )
85- 
86-             with  check :
87-                 check .is_not_none (content , f"❌ Section '{ heading_text }  ' is None" )
88-                 check .not_equal (content , "" , f"❌ Section '{ heading_text }  ' is empty" )
89-                 check .not_equal (content , self .invalid_response , f"❌ '{ heading_text }  ' has invalid response" )
90-                 check .not_equal (content , self .invalid_response1 , f"❌ '{ heading_text }  ' has invalid response" )
101+                 try :
102+                     generate_btn .click ()
103+                     logger .info (f"🔄 Clicked 'Generate' for section '{ title_text }  '" )
104+                 except  Exception  as  e :
105+                     logger .error (f"❌ Failed to click 'Generate' for section '{ title_text }  ': { e }  " )
106+                     continue 
107+ 
108+                 # Retry wait 
109+                 start  =  time .time ()
110+                 while  time .time () -  start  <  max_wait_time :
111+                     try :
112+                         content  =  content_locator .text_content (timeout = 2000 ).strip ()
113+                         if  content :
114+                             logger .info (f"✅ Section '{ title_text }  ' loaded after clicking Generate." )
115+                             content_loaded  =  True 
116+                             break 
117+                     except :
118+                         pass 
119+                     time .sleep (poll_interval )
120+ 
121+                 if  not  content_loaded :
122+                     logger .error (f"❌ Section '{ title_text }  ' still empty after retrying." )
123+ 
124+                     # Optional: take screenshot 
125+                     screenshot_dir  =  "screenshots" 
126+                     os .makedirs (screenshot_dir , exist_ok = True )
127+                     screenshot_path  =  os .path .join (screenshot_dir , f"section_{ index  +  1 }  _{ title_text .replace (' ' , '_' )}  .png" )
128+                     try :
129+                         section .screenshot (path = screenshot_path )
130+                         logger .error (f"📸 Screenshot saved: { screenshot_path }  " )
131+                     except  Exception  as  e :
132+                         logger .error (f"❌ Generate click failed in section '{ title_text }  ': { e }  " )
133+                         continue 
134+ 
135+             try :
136+                     content  =  content_locator .text_content (timeout = 2000 ).strip ()
137+                     with  check :
138+                         if  content  ==  self .invalid_response  or  content  ==  self .invalid_response1 :
139+                             logger .warning (f"❌ Invalid response found in '{ title_text }  '. Retrying Generate + Confirm..." )
140+ 
141+                             try :
142+                                 generate_btn .click ()
143+                                 self .page .wait_for_timeout (3000 )
144+ 
145+                                 confirm_btn  =  self .page .locator ("//button[@class='fui-Button r1alrhcs ___zqkcn80 fd1o0ie fjxutwb fwiml72 fj8njcf fzcpov4 f1d2rq10 f1mk8lai ff3glw6']" )
146+                                 if  confirm_btn .is_visible (timeout = 3000 ):
147+                                     confirm_btn .click ()
148+                                     logger .info (f"🟢 Retried Confirm for section '{ title_text }  '" )
149+                                 else :
150+                                     logger .warning (f"⚠️ Confirm button not visible during retry for '{ title_text }  '" )
151+                             except  Exception  as  e :
152+                                 logger .error (f"❌ Retry Generate/Confirm failed: { e }  " )
153+ 
154+                             retry_start  =  time .time ()
155+                             while  time .time () -  retry_start  <  short_wait :
156+                                 try :
157+                                     content  =  content_locator .text_content (timeout = 2000 ).strip ()
158+                                     if  content  and  content  not  in   [self .invalid_response , self .invalid_response1 ]:
159+                                         logger .info (f"✅ Section '{ title_text }  ' fixed after retry." )
160+                                         break 
161+                                 except :
162+                                     pass 
163+                                 time .sleep (1 )
164+ 
165+                             with  check :
166+                                 check .not_equal (content , self .invalid_response , f"❌ '{ title_text }  ' still has invalid response after retry" )
167+                                 check .not_equal (content , self .invalid_response1 , f"❌ '{ title_text }  ' still has invalid response after retry" )
168+ 
169+                         else :
170+                             logger .info (f"🎯 Section '{ title_text }  ' has valid content." )
171+             except  Exception  as  e :
172+                     logger .error (f"❌ Could not validate content for '{ title_text }  ': { e }  " )
173+ 
174+                     logger .info (f"✔️ Completed section: '{ title_text }  '\n " )
0 commit comments