1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-03-04 16:02:51 +01:00
Files
bec_widgets/tests/unit_tests/test_main_app.py

186 lines
5.4 KiB
Python

import pytest
from qtpy.QtWidgets import QWidget
from bec_widgets.applications.main_app import BECMainApp
from bec_widgets.applications.views.view import ViewBase
from .client_mocks import mocked_client
ANIM_TEST_DURATION = 60 # ms
@pytest.fixture
def viewbase(qtbot):
v = ViewBase(content=QWidget())
qtbot.addWidget(v)
qtbot.waitExposed(v)
yield v
# Spy views for testing enter/exit hooks and veto logic
class SpyView(ViewBase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.enter_calls = 0
self.exit_calls = 0
def on_enter(self) -> None:
self.enter_calls += 1
def on_exit(self) -> bool:
self.exit_calls += 1
return True
class SpyVetoView(SpyView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.allow_exit = False
def on_exit(self) -> bool:
self.exit_calls += 1
return bool(self.allow_exit)
@pytest.fixture
def app_with_spies(qtbot, mocked_client):
app = BECMainApp(client=mocked_client, anim_duration=ANIM_TEST_DURATION, show_examples=False)
qtbot.addWidget(app)
qtbot.waitExposed(app)
app.add_section("Tests", id="tests")
v1 = SpyView(id="v1", title="V1")
v2 = SpyView(id="v2", title="V2")
vv = SpyVetoView(id="vv", title="VV")
app.add_view(icon="widgets", title="View 1", id="v1", widget=v1, mini_text="v1")
app.add_view(icon="widgets", title="View 2", id="v2", widget=v2, mini_text="v2")
app.add_view(icon="widgets", title="Veto View", id="vv", widget=vv, mini_text="vv")
# Start from dock_area (default) to avoid extra enter/exit counts on spies
assert app.stack.currentIndex() == app._view_index["dock_area"]
return app, v1, v2, vv
def test_viewbase_initializes(viewbase):
assert viewbase.on_enter() is None
assert viewbase.on_exit() is True
def test_on_enter_and_on_exit_are_called_on_switch(app_with_spies, qtbot):
app, v1, v2, _ = app_with_spies
app.set_current("v1")
qtbot.wait(10)
assert v1.enter_calls == 1
app.set_current("v2")
qtbot.wait(10)
assert v1.exit_calls == 1
assert v2.enter_calls == 1
app.set_current("v1")
qtbot.wait(10)
assert v2.exit_calls == 1
assert v1.enter_calls == 2
def test_on_exit_veto_prevents_switch_until_allowed(app_with_spies, qtbot):
app, v1, v2, vv = app_with_spies
# Move to veto view first
app.set_current("vv")
qtbot.wait(10)
assert vv.enter_calls == 1
# Attempt to leave veto view -> should veto
app.set_current("v1")
qtbot.wait(10)
assert vv.exit_calls == 1
# Still on veto view because veto returned False
assert app.stack.currentIndex() == app._view_index["vv"]
# Allow exit and try again
vv.allow_exit = True
app.set_current("v1")
qtbot.wait(10)
# Now the switch should have happened, and v1 received on_enter
assert app.stack.currentIndex() == app._view_index["v1"]
assert v1.enter_calls >= 1
def test_guided_tour_is_initialized(app_with_spies):
"""Test that the guided tour is initialized in the main app."""
app, _, _, _ = app_with_spies
# Check that guided_tour exists
assert hasattr(app, "guided_tour")
assert app.guided_tour is not None
# Check that start_guided_tour method exists
assert hasattr(app, "start_guided_tour")
assert callable(app.start_guided_tour)
def test_guided_tour_has_registered_widgets(app_with_spies):
"""Test that the guided tour has registered widgets."""
app, _, _, _ = app_with_spies
# Get registered widgets
registered = app.guided_tour.get_registered_widgets()
# Should have at least some registered widgets
assert len(registered) > 0
# Check that tour steps were created
assert len(app.guided_tour._tour_steps) > 0
def test_views_can_extend_guided_tour(app_with_spies):
"""Test that views can register their own tour steps."""
app, _, _, _ = app_with_spies
# Check that device manager has register_tour_steps method
assert hasattr(app.device_manager, "register_tour_steps")
assert callable(app.device_manager.register_tour_steps)
# Check that developer view has register_tour_steps method
assert hasattr(app.developer_view, "register_tour_steps")
assert callable(app.developer_view.register_tour_steps)
# Verify that calling register_tour_steps returns ViewTourSteps or None
dm_tour = app.device_manager.register_tour_steps(app.guided_tour, app)
if dm_tour is not None:
assert hasattr(dm_tour, "view_title")
assert hasattr(dm_tour, "step_ids")
assert isinstance(dm_tour.step_ids, list)
ide_tour = app.developer_view.register_tour_steps(app.guided_tour, app)
if ide_tour is not None:
assert hasattr(ide_tour, "view_title")
assert hasattr(ide_tour, "step_ids")
assert isinstance(ide_tour.step_ids, list)
def test_guided_tour_can_start_and_stop(app_with_spies, qtbot):
"""Test that the guided tour can be started and stopped."""
app, _, _, _ = app_with_spies
# Start the tour
app.start_guided_tour()
qtbot.wait(100)
# Check that tour is active
assert app.guided_tour._active
assert app.guided_tour.overlay is not None
assert app.guided_tour.overlay.isVisible()
# Stop the tour
app.guided_tour.stop_tour()
qtbot.wait(100)
# Check that tour is stopped
assert not app.guided_tour._active