Skip to content

Commit 567d7e3

Browse files
committed
Guard the Actions-menu tab contract with a headless test
Every registered tab must surface its commands through the Actions menu (registry actions or the menu_actions() hook); a missing hook would silently strand a tab with no reachable commands now that the in-tab buttons are gone.
1 parent cc9bf8a commit 567d7e3

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""GUI smoke tests for the window-level Actions menu tab hooks."""
2+
import os
3+
4+
import pytest
5+
6+
pytest.importorskip("PySide6.QtWidgets")
7+
8+
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
9+
10+
from PySide6.QtWidgets import QApplication # noqa: E402
11+
12+
from je_auto_control.gui.main_widget import AutoControlGUIWidget # noqa: E402
13+
14+
# Interactive panels that intentionally keep their own in-tab layouts
15+
# instead of exposing commands through the Actions menu.
16+
_MENU_EXEMPT_TABS = {"script_builder", "remote_desktop"}
17+
18+
19+
@pytest.fixture(scope="module")
20+
def app():
21+
return QApplication.instance() or QApplication([])
22+
23+
24+
@pytest.fixture(scope="module")
25+
def widget(app):
26+
return AutoControlGUIWidget()
27+
28+
29+
def _entry_actions(entry):
30+
if entry.actions:
31+
return list(entry.actions)
32+
provider = getattr(entry.widget, "menu_actions", None)
33+
return list(provider()) if callable(provider) else []
34+
35+
36+
def test_every_tab_exposes_menu_actions(widget):
37+
missing = [
38+
entry.key for entry in widget._tab_entries
39+
if entry.key not in _MENU_EXEMPT_TABS and not _entry_actions(entry)
40+
]
41+
assert missing == []
42+
43+
44+
def test_menu_actions_are_key_handler_pairs(widget):
45+
for entry in widget._tab_entries:
46+
for action in _entry_actions(entry):
47+
label_key, handler = action
48+
assert isinstance(label_key, str) and label_key
49+
assert callable(handler)
50+
51+
52+
def test_current_tab_menu_actions_follows_active_tab(widget):
53+
record_entry = next(
54+
entry for entry in widget._tab_entries if entry.key == "record"
55+
)
56+
widget.tabs.setCurrentWidget(record_entry.widget)
57+
assert widget.current_tab_menu_actions() == list(record_entry.actions)
58+
59+
60+
def test_hook_tab_actions_reach_the_menu(widget):
61+
widget.show_tab("variables")
62+
entry = next(
63+
entry for entry in widget._tab_entries if entry.key == "variables"
64+
)
65+
widget.tabs.setCurrentWidget(entry.widget)
66+
actions = widget.current_tab_menu_actions()
67+
assert actions == entry.widget.menu_actions()
68+
assert actions, "hook-based tab should surface its actions"

0 commit comments

Comments
 (0)