1+ import atexit
2+ import io
3+ import logging
14import os
25
6+
7+ from bs4 import BeautifulSoup
8+
39from config .constants import URL
410
511from playwright .sync_api import sync_playwright
612
7- from py .xml import html # type: ignore
8-
913import pytest
1014
1115
@@ -31,22 +35,99 @@ def pytest_html_report_title(report):
3135
3236
3337# Add a column for descriptions
34- def pytest_html_results_table_header (cells ):
35- cells .insert (1 , html .th ("Description" ))
38+ # def pytest_html_results_table_header(cells):
39+ # cells.insert(1, html.th("Description"))
3640
3741
38- def pytest_html_results_table_row (report , cells ):
39- cells .insert (
40- 1 , html .td (report .description if hasattr (report , "description" ) else "" )
41- )
42+ # def pytest_html_results_table_row(report, cells):
43+ # cells.insert(
44+ # 1, html.td(report.description if hasattr(report, "description") else "")
45+ # )
46+
47+
48+ log_streams = {}
49+
50+
51+ @pytest .hookimpl (tryfirst = True )
52+ def pytest_runtest_setup (item ):
53+ # Prepare StringIO for capturing logs
54+ stream = io .StringIO ()
55+ handler = logging .StreamHandler (stream )
56+ handler .setLevel (logging .INFO )
57+
58+ logger = logging .getLogger ()
59+ logger .addHandler (handler )
60+
61+ # Save handler and stream
62+ log_streams [item .nodeid ] = (handler , stream )
4263
4364
44- # Add logs and docstring to report
4565@pytest .hookimpl (hookwrapper = True )
4666def pytest_runtest_makereport (item , call ):
4767 outcome = yield
4868 report = outcome .get_result ()
49- report .description = str (item .function .__doc__ )
50- os .makedirs ("logs" , exist_ok = True )
51- extra = getattr (report , "extra" , [])
52- report .extra = extra
69+
70+ handler , stream = log_streams .get (item .nodeid , (None , None ))
71+
72+ if handler and stream :
73+ # Make sure logs are flushed
74+ handler .flush ()
75+ log_output = stream .getvalue ()
76+
77+ # Only remove the handler, don't close the stream yet
78+ logger = logging .getLogger ()
79+ logger .removeHandler (handler )
80+
81+ # Store the log output on the report object for HTML reporting
82+ report .description = f"<pre>{ log_output .strip ()} </pre>"
83+
84+ # Clean up references
85+ log_streams .pop (item .nodeid , None )
86+ else :
87+ report .description = ""
88+
89+
90+ def pytest_collection_modifyitems (items ):
91+ for item in items :
92+ if hasattr (item , 'callspec' ):
93+ prompt = item .callspec .params .get ("prompt" )
94+ if prompt :
95+ item ._nodeid = prompt # This controls how the test name appears in the report
96+
97+
98+ def rename_duration_column ():
99+ report_path = os .path .abspath ("report.html" ) # or your report filename
100+ if not os .path .exists (report_path ):
101+ print ("Report file not found, skipping column rename." )
102+ return
103+
104+ with open (report_path , 'r' , encoding = 'utf-8' ) as f :
105+ soup = BeautifulSoup (f , 'html.parser' )
106+
107+ # Find and rename the header
108+ headers = soup .select ('table#results-table thead th' )
109+ for th in headers :
110+ if th .text .strip () == 'Duration' :
111+ th .string = 'Execution Time'
112+ # print("Renamed 'Duration' to 'Execution Time'")
113+ break
114+ else :
115+ print ("'Duration' column not found in report." )
116+
117+ with open (report_path , 'w' , encoding = 'utf-8' ) as f :
118+ f .write (str (soup ))
119+
120+
121+ # Register this function to run after everything is done
122+ atexit .register (rename_duration_column )
123+
124+
125+ # Add logs and docstring to report
126+ # @pytest.hookimpl(hookwrapper=True)
127+ # def pytest_runtest_makereport(item, call):
128+ # outcome = yield
129+ # report = outcome.get_result()
130+ # report.description = str(item.function.__doc__)
131+ # os.makedirs("logs", exist_ok=True)
132+ # extra = getattr(report, "extra", [])
133+ # report.extra = extra
0 commit comments