131 lines
4.2 KiB
Python
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']
|