11import os
2-
2+ import atexit
3+ import io
4+ from bs4 import BeautifulSoup
5+ import pytest
6+ import logging
37from config .constants import URL
4-
58from playwright .sync_api import sync_playwright
6-
79from py .xml import html # type: ignore
810
9- import pytest
10-
11-
1211@pytest .fixture (scope = "session" )
1312def login_logout ():
1413 # perform login and browser close once in a session
@@ -31,15 +30,87 @@ def pytest_html_report_title(report):
3130
3231
3332# Add a column for descriptions
34- def pytest_html_results_table_header (cells ):
35- cells .insert (1 , html .th ("Description" ))
33+ # def pytest_html_results_table_header(cells):
34+ # cells.insert(1, html.th("Description"))
35+
36+
37+ # def pytest_html_results_table_row(report, cells):
38+ # cells.insert(
39+ # 1, html.td(report.description if hasattr(report, "description") else "")
40+ # )
41+
42+
43+ log_streams = {}
44+
45+ @pytest .hookimpl (tryfirst = True )
46+ def pytest_runtest_setup (item ):
47+ # Prepare StringIO for capturing logs
48+ stream = io .StringIO ()
49+ handler = logging .StreamHandler (stream )
50+ handler .setLevel (logging .INFO )
51+
52+ logger = logging .getLogger ()
53+ logger .addHandler (handler )
54+
55+ # Save handler and stream
56+ log_streams [item .nodeid ] = (handler , stream )
57+
58+
59+ @pytest .hookimpl (hookwrapper = True )
60+ def pytest_runtest_makereport (item , call ):
61+ outcome = yield
62+ report = outcome .get_result ()
63+
64+ handler , stream = log_streams .get (item .nodeid , (None , None ))
65+
66+ if handler and stream :
67+ # Make sure logs are flushed
68+ handler .flush ()
69+ log_output = stream .getvalue ()
70+
71+ # Only remove the handler, don't close the stream yet
72+ logger = logging .getLogger ()
73+ logger .removeHandler (handler )
74+
75+ # Store the log output on the report object for HTML reporting
76+ report .description = f"<pre>{ log_output .strip ()} </pre>"
77+
78+ # Clean up references
79+ log_streams .pop (item .nodeid , None )
80+ else :
81+ report .description = ""
82+
83+ def pytest_collection_modifyitems (items ):
84+ for item in items :
85+ if hasattr (item , 'callspec' ):
86+ prompt = item .callspec .params .get ("prompt" )
87+ if prompt :
88+ item ._nodeid = prompt # This controls how the test name appears in the report
89+
90+ def rename_duration_column ():
91+ report_path = os .path .abspath ("report.html" ) # or your report filename
92+ if not os .path .exists (report_path ):
93+ print ("Report file not found, skipping column rename." )
94+ return
95+
96+ with open (report_path , 'r' , encoding = 'utf-8' ) as f :
97+ soup = BeautifulSoup (f , 'html.parser' )
3698
99+ # Find and rename the header
100+ headers = soup .select ('table#results-table thead th' )
101+ for th in headers :
102+ if th .text .strip () == 'Duration' :
103+ th .string = 'Execution Time'
104+ #print("Renamed 'Duration' to 'Execution Time'")
105+ break
106+ else :
107+ print ("'Duration' column not found in report." )
37108
38- def pytest_html_results_table_row (report , cells ):
39- cells .insert (
40- 1 , html .td (report .description if hasattr (report , "description" ) else "" )
41- )
109+ with open (report_path , 'w' , encoding = 'utf-8' ) as f :
110+ f .write (str (soup ))
42111
112+ # Register this function to run after everything is done
113+ atexit .register (rename_duration_column )
43114
44115# Add logs and docstring to report
45116@pytest .hookimpl (hookwrapper = True )
0 commit comments