mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 19:21:50 +02:00
101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
from unittest import mock
|
|
|
|
import pytest
|
|
from pytestqt.exceptions import TimeoutError as QtBotTimeoutError
|
|
from qtpy.QtCore import QTimer
|
|
from qtpy.QtWidgets import QApplication
|
|
|
|
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
|
from bec_widgets.qt_utils import error_popups
|
|
from bec_widgets.utils import bec_dispatcher as bec_dispatcher_module
|
|
|
|
|
|
class TestableQTimer(QTimer):
|
|
_instances = []
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
TestableQTimer._instances.append(self)
|
|
|
|
@classmethod
|
|
def check_all_stopped(cls, qtbot):
|
|
try:
|
|
qtbot.waitUntil(lambda: all(not timer.isActive() for timer in cls._instances))
|
|
except QtBotTimeoutError as exc:
|
|
raise TimeoutError("Failed to stop all timers") from exc
|
|
cls._instances = []
|
|
|
|
|
|
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
|
def pytest_runtest_makereport(item, call):
|
|
# execute all other hooks to obtain the report object
|
|
outcome = yield
|
|
rep = outcome.get_result()
|
|
|
|
item.stash["failed"] = rep.failed
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def qapplication(qtbot, request): # pylint: disable=unused-argument
|
|
with mock.patch("qtpy.QtCore.QTimer", new=TestableQTimer):
|
|
yield
|
|
|
|
# if the test failed, we don't want to check for open widgets as
|
|
# it simply pollutes the output
|
|
if request.node.stash._storage.get("failed"):
|
|
print("Test failed, skipping cleanup checks")
|
|
return
|
|
|
|
TestableQTimer.check_all_stopped(qtbot)
|
|
|
|
qapp = QApplication.instance()
|
|
qapp.processEvents()
|
|
if hasattr(qapp, "os_listener") and qapp.os_listener:
|
|
qapp.removeEventFilter(qapp.os_listener)
|
|
try:
|
|
qtbot.waitUntil(lambda: qapp.topLevelWidgets() == [])
|
|
except QtBotTimeoutError as exc:
|
|
raise TimeoutError(f"Failed to close all widgets: {qapp.topLevelWidgets()}") from exc
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def rpc_register():
|
|
yield RPCRegister()
|
|
RPCRegister.reset_singleton()
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def bec_dispatcher(threads_check): # pylint: disable=unused-argument
|
|
bec_dispatcher = bec_dispatcher_module.BECDispatcher()
|
|
yield bec_dispatcher
|
|
bec_dispatcher.disconnect_all()
|
|
# clean BEC client
|
|
bec_dispatcher.client.shutdown()
|
|
# reinitialize singleton for next test
|
|
bec_dispatcher_module.BECDispatcher.reset_singleton()
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def clean_singleton():
|
|
error_popups._popup_utility_instance = None
|
|
|
|
|
|
def create_widget(qtbot, widget, *args, **kwargs):
|
|
"""
|
|
Create a widget and add it to the qtbot for testing. This is a helper function that
|
|
should be used in all tests that require a widget to be created.
|
|
|
|
Args:
|
|
qtbot (fixture): pytest-qt fixture
|
|
widget (QWidget): widget class to be created
|
|
*args: positional arguments for the widget
|
|
**kwargs: keyword arguments for the widget
|
|
|
|
Returns:
|
|
QWidget: the created widget
|
|
"""
|
|
widget = widget(*args, **kwargs)
|
|
qtbot.addWidget(widget)
|
|
qtbot.waitExposed(widget)
|
|
return widget
|