Skip to content

Commit a353c53

Browse files
authored
Merge pull request #3319 from seleniumbase/pytest-report-updates
`pytest` report updates
2 parents f4c3f24 + e87ef69 commit a353c53

File tree

8 files changed

+162
-125
lines changed

8 files changed

+162
-125
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ latest_report
100100
report_archives
101101
archived_reports
102102
html_report.html
103+
last_report.html
103104
report.html
104105
report.xml
105106

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ execnet==2.1.1
4444
iniconfig==2.0.0
4545
pluggy==1.5.0
4646
pytest==8.3.4
47-
pytest-html==4.1.1
47+
pytest-html==4.0.2
4848
pytest-metadata==3.1.1
4949
pytest-ordering==0.6
5050
pytest-rerunfailures==14.0;python_version<"3.9"

seleniumbase/__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.33.4"
2+
__version__ = "4.33.5"

seleniumbase/console_scripts/sb_mkdir.py

+1
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ def main():
259259
data.append("report_archives")
260260
data.append("archived_reports")
261261
data.append("html_report.html")
262+
data.append("last_report.html")
262263
data.append("report.html")
263264
data.append("report.xml")
264265
data.append("dashboard.html")

seleniumbase/core/browser_launcher.py

+64-53
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,63 @@ def verify_pyautogui_has_a_headed_browser(driver):
817817
)
818818

819819

820+
def __install_pyautogui_if_missing():
821+
try:
822+
import pyautogui
823+
with suppress(Exception):
824+
use_pyautogui_ver = constants.PyAutoGUI.VER
825+
if pyautogui.__version__ != use_pyautogui_ver:
826+
del pyautogui
827+
shared_utils.pip_install(
828+
"pyautogui", version=use_pyautogui_ver
829+
)
830+
import pyautogui
831+
except Exception:
832+
print("\nPyAutoGUI required! Installing now...")
833+
shared_utils.pip_install(
834+
"pyautogui", version=constants.PyAutoGUI.VER
835+
)
836+
try:
837+
import pyautogui
838+
except Exception:
839+
if (
840+
IS_LINUX
841+
and hasattr(sb_config, "xvfb")
842+
and hasattr(sb_config, "headed")
843+
and hasattr(sb_config, "headless")
844+
and hasattr(sb_config, "headless2")
845+
and (not sb_config.headed or sb_config.xvfb)
846+
and not (sb_config.headless or sb_config.headless2)
847+
):
848+
from sbvirtualdisplay import Display
849+
xvfb_width = 1366
850+
xvfb_height = 768
851+
if (
852+
hasattr(sb_config, "_xvfb_width")
853+
and sb_config._xvfb_width
854+
and isinstance(sb_config._xvfb_width, int)
855+
and hasattr(sb_config, "_xvfb_height")
856+
and sb_config._xvfb_height
857+
and isinstance(sb_config._xvfb_height, int)
858+
):
859+
xvfb_width = sb_config._xvfb_width
860+
xvfb_height = sb_config._xvfb_height
861+
if xvfb_width < 1024:
862+
xvfb_width = 1024
863+
sb_config._xvfb_width = xvfb_width
864+
if xvfb_height < 768:
865+
xvfb_height = 768
866+
sb_config._xvfb_height = xvfb_height
867+
with suppress(Exception):
868+
xvfb_display = Display(
869+
visible=True,
870+
size=(xvfb_width, xvfb_height),
871+
backend="xvfb",
872+
use_xauth=True,
873+
)
874+
xvfb_display.start()
875+
876+
820877
def install_pyautogui_if_missing(driver):
821878
verify_pyautogui_has_a_headed_browser(driver)
822879
pip_find_lock = fasteners.InterProcessLock(
@@ -829,61 +886,15 @@ def install_pyautogui_if_missing(driver):
829886
# Need write permissions
830887
with suppress(Exception):
831888
make_writable(constants.PipInstall.FINDLOCK)
832-
with pip_find_lock: # Prevent issues with multiple processes
833889
try:
834-
import pyautogui
835-
with suppress(Exception):
836-
use_pyautogui_ver = constants.PyAutoGUI.VER
837-
if pyautogui.__version__ != use_pyautogui_ver:
838-
del pyautogui
839-
shared_utils.pip_install(
840-
"pyautogui", version=use_pyautogui_ver
841-
)
842-
import pyautogui
890+
with pip_find_lock:
891+
pass
843892
except Exception:
844-
print("\nPyAutoGUI required! Installing now...")
845-
shared_utils.pip_install(
846-
"pyautogui", version=constants.PyAutoGUI.VER
847-
)
848-
try:
849-
import pyautogui
850-
except Exception:
851-
if (
852-
IS_LINUX
853-
and hasattr(sb_config, "xvfb")
854-
and hasattr(sb_config, "headed")
855-
and hasattr(sb_config, "headless")
856-
and hasattr(sb_config, "headless2")
857-
and (not sb_config.headed or sb_config.xvfb)
858-
and not (sb_config.headless or sb_config.headless2)
859-
):
860-
from sbvirtualdisplay import Display
861-
xvfb_width = 1366
862-
xvfb_height = 768
863-
if (
864-
hasattr(sb_config, "_xvfb_width")
865-
and sb_config._xvfb_width
866-
and isinstance(sb_config._xvfb_width, int)
867-
and hasattr(sb_config, "_xvfb_height")
868-
and sb_config._xvfb_height
869-
and isinstance(sb_config._xvfb_height, int)
870-
):
871-
xvfb_width = sb_config._xvfb_width
872-
xvfb_height = sb_config._xvfb_height
873-
if xvfb_width < 1024:
874-
xvfb_width = 1024
875-
sb_config._xvfb_width = xvfb_width
876-
if xvfb_height < 768:
877-
xvfb_height = 768
878-
sb_config._xvfb_height = xvfb_height
879-
with suppress(Exception):
880-
xvfb_display = Display(
881-
visible=True,
882-
size=(xvfb_width, xvfb_height),
883-
backend="xvfb",
884-
use_xauth=True,
885-
)
886-
xvfb_display.start()
893+
# Since missing permissions, skip the locks
894+
__install_pyautogui_if_missing()
895+
return
896+
with pip_find_lock: # Prevent issues with multiple processes
897+
__install_pyautogui_if_missing()
887898

888899

889900
def get_configured_pyautogui(pyautogui_copy):

seleniumbase/fixtures/base_case.py

+79-69
Original file line numberDiff line numberDiff line change
@@ -13974,12 +13974,82 @@ def __activate_standard_virtual_display(self):
1397413974
self.headless_active = True
1397513975
sb_config.headless_active = True
1397613976

13977+
def __activate_virtual_display(self):
13978+
if self.undetectable and not (self.headless or self.headless2):
13979+
from sbvirtualdisplay import Display
13980+
import Xlib.display
13981+
try:
13982+
if not self._xvfb_width:
13983+
self._xvfb_width = 1366
13984+
if not self._xvfb_height:
13985+
self._xvfb_height = 768
13986+
self._xvfb_display = Display(
13987+
visible=True,
13988+
size=(self._xvfb_width, self._xvfb_height),
13989+
backend="xvfb",
13990+
use_xauth=True,
13991+
)
13992+
self._xvfb_display.start()
13993+
if "DISPLAY" not in os.environ.keys():
13994+
print(
13995+
"\nX11 display failed! Will use regular xvfb!"
13996+
)
13997+
self.__activate_standard_virtual_display()
13998+
except Exception as e:
13999+
if hasattr(e, "msg"):
14000+
print("\n" + str(e.msg))
14001+
else:
14002+
print(e)
14003+
print("\nX11 display failed! Will use regular xvfb!")
14004+
self.__activate_standard_virtual_display()
14005+
return
14006+
pyautogui_is_installed = False
14007+
try:
14008+
import pyautogui
14009+
with suppress(Exception):
14010+
use_pyautogui_ver = constants.PyAutoGUI.VER
14011+
if pyautogui.__version__ != use_pyautogui_ver:
14012+
del pyautogui # To get newer ver
14013+
shared_utils.pip_install(
14014+
"pyautogui", version=use_pyautogui_ver
14015+
)
14016+
import pyautogui
14017+
pyautogui_is_installed = True
14018+
except Exception:
14019+
message = (
14020+
"PyAutoGUI is required for UC Mode on Linux! "
14021+
"Installing now..."
14022+
)
14023+
print("\n" + message)
14024+
shared_utils.pip_install(
14025+
"pyautogui", version=constants.PyAutoGUI.VER
14026+
)
14027+
import pyautogui
14028+
pyautogui_is_installed = True
14029+
if (
14030+
pyautogui_is_installed
14031+
and hasattr(pyautogui, "_pyautogui_x11")
14032+
):
14033+
try:
14034+
pyautogui._pyautogui_x11._display = (
14035+
Xlib.display.Display(os.environ['DISPLAY'])
14036+
)
14037+
sb_config._pyautogui_x11_display = (
14038+
pyautogui._pyautogui_x11._display
14039+
)
14040+
except Exception as e:
14041+
if hasattr(e, "msg"):
14042+
print("\n" + str(e.msg))
14043+
else:
14044+
print(e)
14045+
else:
14046+
self.__activate_standard_virtual_display()
14047+
1397714048
def __activate_virtual_display_as_needed(self):
1397814049
"""This is only needed on Linux.
1397914050
The "--xvfb" arg is still useful, as it prevents headless mode,
1398014051
which is the default mode on Linux unless using another arg."""
1398114052
if "linux" in sys.platform and (not self.headed or self.xvfb):
13982-
from sbvirtualdisplay import Display
1398314053
pip_find_lock = fasteners.InterProcessLock(
1398414054
constants.PipInstall.FINDLOCK
1398514055
)
@@ -13992,75 +14062,15 @@ def __activate_virtual_display_as_needed(self):
1399214062
mode = os.stat(constants.PipInstall.FINDLOCK).st_mode
1399314063
mode |= (mode & 0o444) >> 1 # copy R bits to W
1399414064
os.chmod(constants.PipInstall.FINDLOCK, mode)
14065+
try:
14066+
with pip_find_lock:
14067+
pass
14068+
except Exception:
14069+
# Since missing permissions, skip the locks
14070+
self.__activate_virtual_display()
14071+
return
1399514072
with pip_find_lock: # Prevent issues with multiple processes
13996-
if self.undetectable and not (self.headless or self.headless2):
13997-
import Xlib.display
13998-
try:
13999-
if not self._xvfb_width:
14000-
self._xvfb_width = 1366
14001-
if not self._xvfb_height:
14002-
self._xvfb_height = 768
14003-
self._xvfb_display = Display(
14004-
visible=True,
14005-
size=(self._xvfb_width, self._xvfb_height),
14006-
backend="xvfb",
14007-
use_xauth=True,
14008-
)
14009-
self._xvfb_display.start()
14010-
if "DISPLAY" not in os.environ.keys():
14011-
print(
14012-
"\nX11 display failed! Will use regular xvfb!"
14013-
)
14014-
self.__activate_standard_virtual_display()
14015-
except Exception as e:
14016-
if hasattr(e, "msg"):
14017-
print("\n" + str(e.msg))
14018-
else:
14019-
print(e)
14020-
print("\nX11 display failed! Will use regular xvfb!")
14021-
self.__activate_standard_virtual_display()
14022-
return
14023-
pyautogui_is_installed = False
14024-
try:
14025-
import pyautogui
14026-
with suppress(Exception):
14027-
use_pyautogui_ver = constants.PyAutoGUI.VER
14028-
if pyautogui.__version__ != use_pyautogui_ver:
14029-
del pyautogui # To get newer ver
14030-
shared_utils.pip_install(
14031-
"pyautogui", version=use_pyautogui_ver
14032-
)
14033-
import pyautogui
14034-
pyautogui_is_installed = True
14035-
except Exception:
14036-
message = (
14037-
"PyAutoGUI is required for UC Mode on Linux! "
14038-
"Installing now..."
14039-
)
14040-
print("\n" + message)
14041-
shared_utils.pip_install(
14042-
"pyautogui", version=constants.PyAutoGUI.VER
14043-
)
14044-
import pyautogui
14045-
pyautogui_is_installed = True
14046-
if (
14047-
pyautogui_is_installed
14048-
and hasattr(pyautogui, "_pyautogui_x11")
14049-
):
14050-
try:
14051-
pyautogui._pyautogui_x11._display = (
14052-
Xlib.display.Display(os.environ['DISPLAY'])
14053-
)
14054-
sb_config._pyautogui_x11_display = (
14055-
pyautogui._pyautogui_x11._display
14056-
)
14057-
except Exception as e:
14058-
if hasattr(e, "msg"):
14059-
print("\n" + str(e.msg))
14060-
else:
14061-
print(e)
14062-
else:
14063-
self.__activate_standard_virtual_display()
14073+
self.__activate_virtual_display()
1406414074

1406514075
def __ad_block_as_needed(self):
1406614076
"""This is an internal method for handling ad-blocking.

seleniumbase/plugins/pytest_plugin.py

+14
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,7 @@ def pytest_configure(config):
17091709
sb_config._saved_dashboard_pie = None # Copy of pie chart for html report
17101710
sb_config._dash_final_summary = None # Dash status to add to html report
17111711
sb_config._html_report_name = None # The name of the pytest html report
1712+
sb_config._html_report_copy = None # The copy of the pytest html report
17121713

17131714
arg_join = " ".join(sys_argv)
17141715
if (
@@ -1742,6 +1743,7 @@ def pytest_configure(config):
17421743
if sb_config.dashboard:
17431744
if sb_config._html_report_name == "dashboard.html":
17441745
sb_config._dash_is_html_report = True
1746+
sb_config._html_report_copy = "last_report.html"
17451747

17461748
# Recorder Mode does not support multi-threaded / multi-process runs.
17471749
if sb_config.recorder_mode and sb_config._multithreaded:
@@ -2151,6 +2153,10 @@ def _perform_pytest_unconfigure_(config):
21512153
html_report_path = os.path.join(
21522154
abs_path, sb_config._html_report_name
21532155
)
2156+
if sb_config._html_report_copy:
2157+
html_report_path_copy = os.path.join(
2158+
abs_path, sb_config._html_report_copy
2159+
)
21542160
if (
21552161
sb_config._using_html_report
21562162
and html_report_path
@@ -2201,6 +2207,8 @@ def _perform_pytest_unconfigure_(config):
22012207
)
22022208
with open(html_report_path, "w", encoding="utf-8") as f:
22032209
f.write(the_html_r) # Finalize the HTML report
2210+
with open(html_report_path_copy, "w", encoding="utf-8") as f:
2211+
f.write(the_html_r) # Finalize the HTML report
22042212
# Done with "pytest_unconfigure" unless using the Dashboard
22052213
return
22062214
stamp = ""
@@ -2288,6 +2296,10 @@ def _perform_pytest_unconfigure_(config):
22882296
html_report_path = os.path.join(
22892297
abs_path, sb_config._html_report_name
22902298
)
2299+
if sb_config._html_report_copy:
2300+
html_report_path_copy = os.path.join(
2301+
abs_path, sb_config._html_report_copy
2302+
)
22912303
if (
22922304
sb_config._using_html_report
22932305
and html_report_path
@@ -2358,6 +2370,8 @@ def _perform_pytest_unconfigure_(config):
23582370
)
23592371
with open(html_report_path, "w", encoding="utf-8") as f:
23602372
f.write(the_html_r) # Finalize the HTML report
2373+
with open(html_report_path_copy, "w", encoding="utf-8") as f:
2374+
f.write(the_html_r) # Finalize the HTML report
23612375
except KeyboardInterrupt:
23622376
pass
23632377
except Exception:

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@
193193
'iniconfig==2.0.0',
194194
'pluggy==1.5.0',
195195
'pytest==8.3.4',
196-
"pytest-html==4.1.1",
196+
"pytest-html==4.0.2",
197197
'pytest-metadata==3.1.1',
198198
"pytest-ordering==0.6",
199199
'pytest-rerunfailures==14.0;python_version<"3.9"',

0 commit comments

Comments
 (0)