Files
navipy/tests/test_accessible_tree.py

131 lines
4.2 KiB
Python

"""Tree navigation and accessibility regressions, without a server or audio."""
import pytest
from PySide6.QtCore import Qt
from PySide6.QtGui import QAccessible
from PySide6.QtTest import QTest
from PySide6.QtWidgets import QApplication, QTreeWidgetItem
from src.accessibility.accessible_tree import AccessibleTreeWidget
@pytest.fixture
def tree():
app = QApplication.instance() or QApplication([])
widget = AccessibleTreeWidget()
widget.setHeaderHidden(True)
widget.show()
app.processEvents()
yield widget
widget.close()
def add(parent, text):
item = QTreeWidgetItem([text])
if isinstance(parent, AccessibleTreeWidget):
parent.addTopLevelItem(item)
else:
parent.addChild(item)
return item
def press(tree, key, expected):
QTest.keyClick(tree, key)
assert tree.currentItem() is expected
def test_collapsed_children_and_late_results_are_not_navigable(tree):
root = add(tree, 'Albums')
child = add(root, 'Album')
last = add(tree, 'Playlists')
tree.setCurrentItem(root)
press(tree, Qt.Key_Down, last)
press(tree, Qt.Key_Up, root)
press(tree, Qt.Key_Right, root)
press(tree, Qt.Key_Right, child)
root.setExpanded(False)
assert tree.currentItem() is root
late = add(root, 'Loaded after collapse')
assert not tree.isItemNavigable(late)
press(tree, Qt.Key_Down, last)
root.setExpanded(True)
assert tree.isItemNavigable(late)
def test_hidden_rows_are_skipped_in_both_directions_and_at_edges(tree):
hidden_first = add(tree, 'Hidden first')
hidden_first.setHidden(True)
root = add(tree, 'Root')
hidden_child = add(root, 'Hidden child')
hidden_child.setHidden(True)
child = add(root, 'Visible child')
disabled = add(root, 'Disabled')
disabled.setDisabled(True)
other = add(root, 'Other child')
hidden_last = add(tree, 'Hidden last')
hidden_last.setHidden(True)
root.setExpanded(True)
tree.setCurrentItem(root)
press(tree, Qt.Key_Right, child)
press(tree, Qt.Key_Down, other)
press(tree, Qt.Key_Up, child)
press(tree, Qt.Key_Home, root)
press(tree, Qt.Key_End, other)
press(tree, Qt.Key_PageUp, root)
press(tree, Qt.Key_PageDown, other)
def test_expansion_preserves_names_descriptions_and_flags(tree):
root = add(tree, 'Artist')
root.setData(0, Qt.AccessibleTextRole, 'Artist, 12 albums')
child = add(root, 'Album')
child.setData(0, Qt.AccessibleDescriptionRole, 'Released in 2024')
child.setFlags(child.flags() & ~Qt.ItemIsSelectable)
disabled = add(root, 'Unavailable')
disabled.setDisabled(True)
original_flags = [child.flags(), disabled.flags()]
states = []
tree.itemStateChanged.connect(lambda item, state: states.append(state))
for _ in range(2):
root.setExpanded(True)
root.setExpanded(False)
assert root.data(0, Qt.AccessibleTextRole) == 'Artist, 12 albums'
assert child.data(0, Qt.AccessibleDescriptionRole) == 'Released in 2024'
assert [child.flags(), disabled.flags()] == original_flags
assert states == ['expanded', 'collapsed'] * 2
def test_nested_collapsed_branch_stays_closed_on_parent_reopen(tree):
root = add(tree, 'Root')
branch = add(root, 'Branch')
leaf = add(branch, 'Leaf')
root.setExpanded(True)
branch.setExpanded(True)
tree.setCurrentItem(leaf)
branch.setExpanded(False)
assert tree.currentItem() is branch
root.setExpanded(False)
root.setExpanded(True)
assert not tree.isItemNavigable(leaf)
tree.setCurrentItem(branch)
press(tree, Qt.Key_End, branch)
def test_accessibility_exposes_only_expanded_rows(tree):
root = add(tree, 'Albums')
add(root, 'Song')
tree.setCurrentItem(root)
QApplication.processEvents()
interface = QAccessible.queryAccessibleInterface(tree)
def spoken_rows():
return [interface.child(i).text(QAccessible.Name)
for i in range(interface.childCount())
if interface.child(i).role() == QAccessible.TreeItem]
assert spoken_rows() == ['Albums']
root.setExpanded(True)
QApplication.processEvents()
assert spoken_rows() == ['Albums', 'Song']
root.setExpanded(False)
QApplication.processEvents()
assert spoken_rows() == ['Albums']