zapretgui/tests/test_accessibility_helpers.py
2026-07-06 23:23:23 +03:00

779 lines
30 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from pathlib import Path
import unittest
class _Widget:
def __init__(self, text: str = "") -> None:
self._text = str(text)
self.accessible_name = ""
self.accessible_description = ""
self.tooltip = ""
self.properties: dict[str, object] = {}
self.property_calls: list[tuple[str, object]] = []
def text(self) -> str:
return self._text
def setText(self, text: str) -> None: # noqa: N802
self._text = str(text)
def accessibleName(self) -> str: # noqa: N802
return self.accessible_name
def setAccessibleName(self, text: str) -> None: # noqa: N802
self.accessible_name = str(text)
def accessibleDescription(self) -> str: # noqa: N802
return self.accessible_description
def setAccessibleDescription(self, text: str) -> None: # noqa: N802
self.accessible_description = str(text)
def toolTip(self) -> str: # noqa: N802
return self.tooltip
def setToolTip(self, text: str) -> None: # noqa: N802
self.tooltip = str(text)
def property(self, name: str): # noqa: A003
return self.properties.get(str(name))
def setProperty(self, name: str, value) -> None: # noqa: N802
self.property_calls.append((str(name), value))
self.properties[str(name)] = value
class AccessibilityHelpersTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtWidgets import QApplication
cls._app = QApplication.instance() or QApplication([])
def test_set_accessible_name_uses_widget_text_by_default(self) -> None:
from ui.accessibility import set_accessible_name
widget = _Widget("Запустить")
changed = set_accessible_name(widget)
self.assertTrue(changed)
self.assertEqual(widget.accessible_name, "Запустить")
def test_set_accessible_description_skips_duplicate_value(self) -> None:
from ui.accessibility import set_accessible_description
widget = _Widget()
widget.accessible_description = "Открывает папку с логами"
changed = set_accessible_description(widget, "Открывает папку с логами")
self.assertFalse(changed)
self.assertEqual(widget.accessible_description, "Открывает папку с логами")
def test_set_control_accessibility_sets_name_and_description(self) -> None:
from ui.accessibility import set_control_accessibility
widget = _Widget("Остановить")
set_control_accessibility(
widget,
name="Остановить Zapret",
description="Останавливает запущенный процесс обхода блокировок.",
)
self.assertEqual(widget.accessible_name, "Остановить Zapret")
self.assertEqual(widget.accessible_description, "Останавливает запущенный процесс обхода блокировок.")
def test_set_control_accessibility_enables_enter_for_push_button(self) -> None:
from PyQt6.QtCore import Qt
from PyQt6.QtTest import QTest
from qfluentwidgets import PushButton
from ui.accessibility import set_control_accessibility
button = PushButton("Открыть")
self.addCleanup(button.deleteLater)
clicked: list[bool] = []
button.clicked.connect(lambda: clicked.append(True))
set_control_accessibility(button, name="Открыть логи")
button.show()
self._app.processEvents()
button.setFocus()
self._app.processEvents()
QTest.keyClick(button, Qt.Key.Key_Return)
self._app.processEvents()
self.assertEqual(clicked, [True])
def test_set_control_accessibility_adds_default_keyboard_hint_for_clickable_button(self) -> None:
from qfluentwidgets import PushButton
from ui.accessibility import set_control_accessibility
button = PushButton("Открыть")
self.addCleanup(button.deleteLater)
set_control_accessibility(button, name="Открыть логи")
self.assertEqual(
button.accessibleDescription(),
"Нажмите Enter или Пробел, чтобы выполнить действие.",
)
def test_set_control_accessibility_adds_default_keyboard_hint_for_toggle(self) -> None:
from qfluentwidgets import CheckBox
from ui.accessibility import set_control_accessibility
checkbox = CheckBox("Включить")
self.addCleanup(checkbox.deleteLater)
set_control_accessibility(checkbox, name="Автозапуск, выключено")
self.assertEqual(
checkbox.accessibleDescription(),
"Нажмите Enter или Пробел, чтобы переключить.",
)
def test_set_control_accessibility_updates_checkable_state_after_enter(self) -> None:
from PyQt6.QtCore import Qt
from PyQt6.QtTest import QTest
from qfluentwidgets import CheckBox
from ui.accessibility import set_control_accessibility
checkbox = CheckBox("Пропускать проблемные домены")
self.addCleanup(checkbox.deleteLater)
checkbox.setChecked(False)
set_control_accessibility(
checkbox,
name="Пропускать проблемные домены, выключено",
description="Если включено, BlockCheck пропускает домены с ошибками.",
)
checkbox.show()
self._app.processEvents()
checkbox.setFocus()
self._app.processEvents()
QTest.keyClick(checkbox, Qt.Key.Key_Return)
self._app.processEvents()
self.assertTrue(checkbox.isChecked())
self.assertEqual(checkbox.accessibleName(), "Пропускать проблемные домены, включено")
self.assertEqual(
checkbox.property("screenReaderStateText"),
"Пропускать проблемные домены, включено",
)
def test_set_control_accessibility_enables_tab_and_enter_for_clickable_widget(self) -> None:
from PyQt6.QtCore import QEvent, Qt, pyqtSignal
from PyQt6.QtGui import QKeyEvent
from PyQt6.QtWidgets import QWidget
from ui.accessibility import set_control_accessibility
class ClickablePanel(QWidget):
clicked = pyqtSignal()
panel = ClickablePanel()
self.addCleanup(panel.deleteLater)
panel.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
clicked: list[bool] = []
panel.clicked.connect(lambda: clicked.append(True))
set_control_accessibility(panel, name="Открыть раздел: Логи")
event = QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_Return, Qt.KeyboardModifier.NoModifier)
panel.keyPressEvent(event)
self.assertEqual(panel.focusPolicy(), Qt.FocusPolicy.StrongFocus)
self.assertTrue(event.isAccepted())
self.assertEqual(clicked, [True])
def test_set_control_accessibility_enables_enter_for_widget_with_click_method(self) -> None:
from PyQt6.QtCore import QEvent, Qt
from PyQt6.QtGui import QKeyEvent
from PyQt6.QtWidgets import QWidget
from ui.accessibility import set_control_accessibility
class ClickMethodPanel(QWidget):
def __init__(self) -> None:
super().__init__()
self.click_count = 0
def click(self) -> None:
self.click_count += 1
panel = ClickMethodPanel()
self.addCleanup(panel.deleteLater)
panel.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
set_control_accessibility(panel, name="Открыть раздел: Настройки")
event = QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_Return, Qt.KeyboardModifier.NoModifier)
panel.keyPressEvent(event)
self.assertEqual(panel.focusPolicy(), Qt.FocusPolicy.StrongFocus)
self.assertTrue(event.isAccepted())
self.assertEqual(panel.click_count, 1)
def test_keyboard_click_survives_late_key_handler_replacement(self) -> None:
from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtTest import QTest
from PyQt6.QtWidgets import QWidget
from ui.accessibility import set_control_accessibility
class ClickablePanel(QWidget):
clicked = pyqtSignal()
panel = ClickablePanel()
self.addCleanup(panel.deleteLater)
clicked: list[bool] = []
panel.clicked.connect(lambda: clicked.append(True))
set_control_accessibility(panel, name="Открыть раздел: Логи")
panel.keyPressEvent = lambda event: event.ignore()
panel.show()
self._app.processEvents()
panel.setFocus()
self._app.processEvents()
QTest.keyClick(panel, Qt.Key.Key_Return)
self._app.processEvents()
self.assertEqual(clicked, [True])
def test_set_control_accessibility_names_spinbox_inner_field_and_skips_buttons(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import SpinBox
from ui.accessibility import set_control_accessibility
spinbox = SpinBox()
self.addCleanup(spinbox.deleteLater)
set_control_accessibility(
spinbox,
name="Номер стратегии, выбрано: 3",
description="Стрелками вверх и вниз можно изменить номер стратегии.",
)
line_edit = spinbox.findChild(object, "qt_spinbox_lineedit")
buttons = [
child
for child in spinbox.findChildren(object)
if type(child).__name__ == "SpinButton"
and hasattr(child, "setFocusPolicy")
]
self.assertIsNotNone(line_edit)
self.assertEqual(line_edit.accessibleName(), "Номер стратегии, выбрано: 3")
self.assertIn("Стрелками вверх и вниз", line_edit.accessibleDescription())
self.assertTrue(buttons)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_set_control_accessibility_skips_line_edit_clear_button_in_tab_order(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import LineEdit
from ui.accessibility import set_control_accessibility
line_edit = LineEdit()
self.addCleanup(line_edit.deleteLater)
set_control_accessibility(line_edit, name="Домен для белого списка")
buttons = [
child
for child in line_edit.findChildren(object)
if str(getattr(child, "objectName", lambda: "")() or "") == "lineEditButton"
and hasattr(child, "setFocusPolicy")
]
self.assertTrue(buttons)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_set_control_accessibility_skips_plain_text_edit_scrollbar_arrows(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import PlainTextEdit
from ui.accessibility import set_control_accessibility
text_edit = PlainTextEdit()
self.addCleanup(text_edit.deleteLater)
set_control_accessibility(text_edit, name="История рейтингов стратегий")
buttons = [
child
for child in text_edit.findChildren(object)
if type(child).__name__ == "ArrowButton"
and hasattr(child, "setFocusPolicy")
]
self.assertTrue(buttons)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_set_state_text_marks_text_status_for_screen_reader(self) -> None:
from ui.accessibility import set_state_text
widget = _Widget()
set_state_text(widget, "Запущено")
self.assertEqual(widget.accessible_name, "Запущено")
self.assertEqual(widget.properties["screenReaderStateText"], "Запущено")
def test_set_state_text_skips_line_edit_clear_button_in_tab_order(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import LineEdit
from ui.accessibility import set_state_text
line_edit = LineEdit()
self.addCleanup(line_edit.deleteLater)
set_state_text(line_edit, "Код привязки Premium: пока не создан")
buttons = [
child
for child in line_edit.findChildren(object)
if str(getattr(child, "objectName", lambda: "")() or "") == "lineEditButton"
and hasattr(child, "setFocusPolicy")
]
self.assertTrue(buttons)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_set_state_text_skips_plain_text_edit_scrollbar_arrows(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import PlainTextEdit
from ui.accessibility import set_state_text
text_edit = PlainTextEdit()
self.addCleanup(text_edit.deleteLater)
set_state_text(text_edit, "Лог обучения Оркестратора: пока нет записей обучения")
buttons = [
child
for child in text_edit.findChildren(object)
if type(child).__name__ == "ArrowButton"
and hasattr(child, "setFocusPolicy")
]
self.assertTrue(buttons)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_set_state_text_skips_duplicate_property_write(self) -> None:
from ui.accessibility import set_state_text
widget = _Widget()
widget.accessible_name = "Запущено"
widget.properties["screenReaderStateText"] = "Запущено"
set_state_text(widget, "Запущено")
self.assertEqual(widget.property_calls, [])
def test_set_item_accessible_text_sets_item_roles(self) -> None:
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QTableWidgetItem
from ui.accessibility import set_item_accessible_text
item = QTableWidgetItem("OK")
set_item_accessible_text(item, "Статус: OK", description="Проверка прошла успешно")
self.assertEqual(item.data(Qt.ItemDataRole.AccessibleTextRole), "Статус: OK")
self.assertEqual(item.data(Qt.ItemDataRole.AccessibleDescriptionRole), "Проверка прошла успешно")
def test_remove_line_edit_buttons_from_tab_order_skips_qfluent_search_buttons(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import SearchLineEdit
from ui.accessibility import remove_line_edit_buttons_from_tab_order
search = SearchLineEdit()
self.addCleanup(search.deleteLater)
search.setClearButtonEnabled(True)
search.setText("profile")
search.show()
self._app.processEvents()
buttons = [
child
for child in search.findChildren(object)
if str(getattr(child, "objectName", lambda: "")() or "") == "lineEditButton"
and hasattr(child, "setFocusPolicy")
]
self.assertTrue(buttons)
remove_line_edit_buttons_from_tab_order(search)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_remove_line_edit_buttons_from_tab_order_handles_buttons_created_after_text_change(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import SearchLineEdit
from ui.accessibility import remove_line_edit_buttons_from_tab_order
search = SearchLineEdit()
self.addCleanup(search.deleteLater)
search.setClearButtonEnabled(True)
remove_line_edit_buttons_from_tab_order(search)
search.setText("profile")
self._app.processEvents()
buttons = [
child
for child in search.findChildren(object)
if str(getattr(child, "objectName", lambda: "")() or "") == "lineEditButton"
and hasattr(child, "setFocusPolicy")
]
self.assertTrue(buttons)
self.assertTrue(all(button.focusPolicy() == Qt.FocusPolicy.NoFocus for button in buttons))
def test_set_segmented_items_accessibility_marks_selected_item(self) -> None:
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import SegmentedWidget
from ui.segmented_accessibility import set_segmented_items_accessibility
app = QApplication.instance() or QApplication([])
self.assertIsNotNone(app)
widget = SegmentedWidget()
widget.addItem("first", "Первый")
widget.addItem("second", "Второй")
widget.setCurrentItem("second")
set_segmented_items_accessibility(widget, name="Раздел")
self.assertEqual(widget.items["first"].accessibleName(), "Раздел: Первый, не выбрано")
self.assertEqual(widget.items["second"].accessibleName(), "Раздел: Второй, выбрано")
def test_set_segmented_items_accessibility_accepts_accessible_labels(self) -> None:
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import SegmentedWidget
from ui.segmented_accessibility import set_segmented_items_accessibility
app = QApplication.instance() or QApplication([])
self.assertIsNotNone(app)
widget = SegmentedWidget()
widget.addItem("about", "О ПРОГРАММЕ")
widget.addItem("support", "ПОДДЕРЖКА")
widget.setCurrentItem("about")
set_segmented_items_accessibility(
widget,
name="Вкладки",
labels={
"about": "О программе",
"support": "Поддержка",
},
)
self.assertEqual(widget.items["about"].accessibleName(), "Вкладки: О программе, выбрано")
self.assertEqual(widget.items["support"].accessibleName(), "Вкладки: Поддержка, не выбрано")
def test_set_segmented_items_accessibility_enables_keyboard_selection(self) -> None:
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtCore import QEvent, Qt
from PyQt6.QtGui import QKeyEvent
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import SegmentedWidget
from ui.segmented_accessibility import set_segmented_items_accessibility
app = QApplication.instance() or QApplication([])
self.assertIsNotNone(app)
selected: list[str] = []
widget = SegmentedWidget()
widget.addItem("first", "Первый", lambda: selected.append("first"))
widget.addItem("second", "Второй", lambda: selected.append("second"))
widget.setCurrentItem("first")
set_segmented_items_accessibility(widget, name="Раздел")
right_event = QKeyEvent(QEvent.Type.KeyPress, int(Qt.Key.Key_Right), Qt.KeyboardModifier.NoModifier)
QApplication.sendEvent(widget.items["first"], right_event)
self.assertTrue(right_event.isAccepted())
self.assertEqual(widget.currentRouteKey(), "second")
self.assertEqual(selected, ["second"])
enter_event = QKeyEvent(QEvent.Type.KeyPress, int(Qt.Key.Key_Return), Qt.KeyboardModifier.NoModifier)
QApplication.sendEvent(widget.items["second"], enter_event)
self.assertTrue(enter_event.isAccepted())
self.assertEqual(selected, ["second", "second"])
def test_segmented_keyboard_selection_refreshes_spoken_selected_state(self) -> None:
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtCore import QEvent, Qt
from PyQt6.QtGui import QKeyEvent
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import SegmentedWidget
from ui.segmented_accessibility import set_segmented_items_accessibility
app = QApplication.instance() or QApplication([])
self.assertIsNotNone(app)
widget = SegmentedWidget()
widget.addItem("first", "Первый")
widget.addItem("second", "Второй")
widget.setCurrentItem("first")
set_segmented_items_accessibility(widget, name="Раздел")
event = QKeyEvent(QEvent.Type.KeyPress, int(Qt.Key.Key_Right), Qt.KeyboardModifier.NoModifier)
QApplication.sendEvent(widget.items["first"], event)
self.assertTrue(event.isAccepted())
self.assertEqual(widget.currentRouteKey(), "second")
self.assertEqual(widget.items["first"].accessibleName(), "Раздел: Первый, не выбрано")
self.assertEqual(widget.items["second"].accessibleName(), "Раздел: Второй, выбрано")
def test_segmented_widget_itself_reads_current_selection(self) -> None:
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import SegmentedWidget
from ui.segmented_accessibility import set_segmented_items_accessibility
app = QApplication.instance() or QApplication([])
self.assertIsNotNone(app)
widget = SegmentedWidget()
widget.addItem("first", "Первый")
widget.addItem("second", "Второй")
widget.setCurrentItem("second")
set_segmented_items_accessibility(widget, name="Раздел")
self.assertEqual(widget.accessibleName(), "Раздел, выбрано: Второй")
self.assertEqual(widget.property("screenReaderStateText"), "Раздел, выбрано: Второй")
self.assertIn("стрелками", widget.accessibleDescription())
self.assertIn("Enter или Пробел", widget.accessibleDescription())
def test_combo_items_accessibility_updates_after_selection_change(self) -> None:
from PyQt6.QtCore import Qt
from qfluentwidgets import ComboBox
from ui.combo_accessibility import set_combo_items_accessibility
combo = ComboBox()
self.addCleanup(combo.deleteLater)
combo.addItem("Авто")
combo.addItem("Ручной")
set_combo_items_accessibility(combo, name="Режим запуска")
combo.setCurrentIndex(1)
menu = combo._create_accessible_combo_menu()
self.assertEqual(
menu.view.item(0).data(Qt.ItemDataRole.AccessibleTextRole),
"Режим запуска: Авто, не выбран",
)
self.assertEqual(
menu.view.item(1).data(Qt.ItemDataRole.AccessibleTextRole),
"Режим запуска: Ручной, выбран",
)
menu.deleteLater()
self._app.processEvents()
def test_global_round_menu_hairline_fix_patches_new_menus_once(self) -> None:
from unittest.mock import patch
from qfluentwidgets import Action, RoundMenu
from ui.popup_menu_style import install_global_round_menu_hairline_fix
with (
patch("ui.popup_menu_style._is_windows_11_or_newer", return_value=True),
patch(
"ui.popup_menu_style._round_menu_hairline_border_qss",
return_value="MenuActionListWidget { border-color: rgba(1, 2, 3, 0.40); }",
),
):
install_global_round_menu_hairline_fix()
install_global_round_menu_hairline_fix()
menu = RoundMenu(parent=None)
menu.addAction(Action("Пункт", menu))
self.assertIn("zapretgui-round-menu-hairline-begin", menu.styleSheet())
self.assertEqual(menu.styleSheet().count("zapretgui-round-menu-hairline-begin"), 1)
self.assertEqual(menu.styleSheet().count("rgba(1, 2, 3, 0.40)"), 1)
self.assertIn("border-radius", menu.styleSheet())
menu.deleteLater()
self._app.processEvents()
def test_global_round_menu_hairline_fix_refreshes_existing_menu_style(self) -> None:
from unittest.mock import patch
from qfluentwidgets import RoundMenu
from ui.popup_menu_style import _apply_round_menu_hairline_qss, install_global_round_menu_hairline_fix
with (
patch("ui.popup_menu_style._is_windows_11_or_newer", return_value=True),
patch(
"ui.popup_menu_style._round_menu_hairline_border_qss",
return_value="MenuActionListWidget { border-color: rgba(1, 2, 3, 0.40); }",
),
):
install_global_round_menu_hairline_fix()
menu = RoundMenu(parent=None)
self.assertIn("rgba(1, 2, 3, 0.40)", menu.styleSheet())
import qfluentwidgets.common.style_sheet as fluent_style_sheet
self.assertTrue(
bool(getattr(fluent_style_sheet.setStyleSheet, "_zapretgui_round_menu_hairline_patch_installed", False))
)
with (
patch("ui.popup_menu_style._is_windows_11_or_newer", return_value=True),
patch(
"ui.popup_menu_style._round_menu_hairline_border_qss",
return_value="MenuActionListWidget { border-color: rgba(4, 5, 6, 0.50); }",
),
):
_apply_round_menu_hairline_qss(menu)
self.assertNotIn("rgba(1, 2, 3, 0.40)", menu.styleSheet())
self.assertIn("rgba(4, 5, 6, 0.50)", menu.styleSheet())
self.assertEqual(menu.styleSheet().count("zapretgui-round-menu-hairline-begin"), 1)
menu.deleteLater()
self._app.processEvents()
def test_round_menu_hairline_fix_is_not_called_per_menu(self) -> None:
root = Path(__file__).resolve().parents[1]
for relative_path in (
"src/hosts/ui/services_matrix.py",
"src/ui/combo_accessibility.py",
"src/tray.py",
):
with self.subTest(path=relative_path):
source = (root / relative_path).read_text(encoding="utf-8")
self.assertNotIn("suppress_round_menu_hairline(", source)
def test_startup_installs_global_round_menu_hairline_fix(self) -> None:
root = Path(__file__).resolve().parents[1]
source = (root / "src/main/qt_runtime.py").read_text(encoding="utf-8")
self.assertIn("install_global_round_menu_hairline_fix(app)", source)
self.assertIn("StartupQtRoundMenuHairlineFix", source)
def test_accessible_combo_menu_uses_global_round_menu_hairline_fix(self) -> None:
from unittest.mock import patch
from qfluentwidgets import ComboBox
from ui.combo_accessibility import set_combo_items_accessibility
from ui.popup_menu_style import install_global_round_menu_hairline_fix
combo = ComboBox()
self.addCleanup(combo.deleteLater)
combo.addItem("Авто")
combo.addItem("Ручной")
with patch("ui.popup_menu_style._is_windows_11_or_newer", return_value=True):
install_global_round_menu_hairline_fix()
set_combo_items_accessibility(combo, name="Режим запуска")
menu = combo._create_accessible_combo_menu()
self.assertIn("MenuActionListWidget", menu.styleSheet())
self.assertIn("border-color", menu.styleSheet())
self.assertIn("zapretgui-round-menu-hairline-begin", menu.styleSheet())
self.assertNotIn("border-left", menu.styleSheet())
menu.deleteLater()
self._app.processEvents()
def test_combo_widget_itself_reads_current_selection(self) -> None:
from qfluentwidgets import ComboBox
from ui.combo_accessibility import set_combo_items_accessibility
combo = ComboBox()
self.addCleanup(combo.deleteLater)
combo.addItem("Авто")
combo.addItem("Ручной")
combo.setCurrentIndex(1)
set_combo_items_accessibility(combo, name="Режим запуска")
self.assertEqual(combo.accessibleName(), "Режим запуска, выбрано: Ручной")
self.assertEqual(combo.property("screenReaderStateText"), "Режим запуска, выбрано: Ручной")
self.assertIn("стрелками", combo.accessibleDescription())
self.assertIn("Enter", combo.accessibleDescription())
def test_set_tooltip_also_sets_accessible_description(self) -> None:
from unittest.mock import patch
from ui.fluent_widgets import set_tooltip
widget = _Widget()
widget.installEventFilter = lambda _filter: None
with patch("ui.fluent_widgets.ToolTipFilter", return_value=object()):
set_tooltip(widget, "Открывает папку с логами.")
self.assertEqual(widget.tooltip, "Открывает папку с логами.")
self.assertEqual(widget.accessible_description, "Открывает папку с логами.")
def test_set_tooltip_sets_accessible_name_for_icon_only_controls(self) -> None:
from unittest.mock import patch
from ui.fluent_widgets import set_tooltip
widget = _Widget("")
widget.installEventFilter = lambda _filter: None
with patch("ui.fluent_widgets.ToolTipFilter", return_value=object()):
set_tooltip(widget, "Создать новый preset")
self.assertEqual(widget.accessible_name, "Создать новый preset")
if __name__ == "__main__":
unittest.main()