Updated tests.
This commit is contained in:
@@ -11,7 +11,7 @@ gi.require_version("Atspi", "2.0")
|
||||
from gi.repository import Atspi
|
||||
|
||||
from cthulhu import cthulhu_state
|
||||
from cthulhu.ax_utilities_event import AXUtilitiesEvent
|
||||
from cthulhu.ax_utilities_event import AXUtilitiesEvent, TextEventReason
|
||||
from cthulhu.scripts import default
|
||||
from cthulhu.scripts.toolkits.Chromium import script as chromium_script
|
||||
from cthulhu.scripts.toolkits.Gecko import script as gecko_script
|
||||
@@ -187,6 +187,222 @@ class ChromiumTabFocusSequenceTests(unittest.TestCase):
|
||||
self._assert_tab_caret_focused_sequence_presents_once(radio)
|
||||
|
||||
|
||||
class FocusedChangeInteractionSequenceTests(unittest.TestCase):
|
||||
"""Ordered ownership contracts around focused-change events."""
|
||||
|
||||
@staticmethod
|
||||
def _make_script(
|
||||
document: object,
|
||||
caretContext: FakeAccessible,
|
||||
) -> chromium_script.Script:
|
||||
testScript = chromium_script.Script.__new__(chromium_script.Script)
|
||||
testScript._lastCommandWasCaretNav = False
|
||||
testScript._lastCommandWasStructNav = False
|
||||
testScript._lastCommandWasMouseButton = False
|
||||
testScript._browseModeIsSticky = False
|
||||
testScript._clearSyntheticWebSelection = mock.Mock()
|
||||
testScript.refreshKeyGrabs = mock.Mock()
|
||||
testScript.utilities = mock.Mock()
|
||||
testScript.utilities.isDocument.return_value = False
|
||||
testScript.utilities.isStaticTextLeaf.return_value = False
|
||||
testScript.utilities.isRedundantAutocompleteEvent.return_value = False
|
||||
testScript.utilities.isZombie.return_value = False
|
||||
testScript.utilities.getTopLevelDocumentForObject.return_value = document
|
||||
testScript.utilities.getDocumentForObject.return_value = document
|
||||
testScript.utilities.getCaretContext.return_value = (caretContext, 0)
|
||||
testScript.utilities.lastInputEventWasCaretNavWithSelection.return_value = False
|
||||
testScript.utilities.lastInputEventWasCharNav.return_value = False
|
||||
testScript.utilities.inFindContainer.return_value = False
|
||||
testScript.utilities.eventIsFromLocusOfFocusDocument.return_value = True
|
||||
testScript.utilities.isWebAppDescendant.return_value = False
|
||||
testScript.utilities.handleEventFromContextReplicant.return_value = False
|
||||
testScript.utilities.lastInputEventWasPageNav.return_value = False
|
||||
testScript.utilities.isAnchor.return_value = False
|
||||
testScript.utilities.isLink.return_value = False
|
||||
testScript.utilities.isChildOfCurrentFragment.return_value = False
|
||||
testScript.utilities.documentFragment.return_value = ""
|
||||
return testScript
|
||||
|
||||
def _assert_navigation_command_owns_caret_and_focus_pair(
|
||||
self,
|
||||
*,
|
||||
caretNavigation: bool,
|
||||
structuralNavigation: bool,
|
||||
) -> None:
|
||||
document = object()
|
||||
target = FakeAccessible(Atspi.Role.PARAGRAPH)
|
||||
testScript = self._make_script(document, target)
|
||||
testScript._lastCommandWasCaretNav = caretNavigation
|
||||
testScript._lastCommandWasStructNav = structuralNavigation
|
||||
events = [
|
||||
FakeEvent("object:text-caret-moved", target, detail1=4),
|
||||
FakeEvent("object:state-changed:focused", target, detail1=1),
|
||||
]
|
||||
presentations = ["navigation-command"]
|
||||
|
||||
with (
|
||||
mock.patch.object(cthulhu_state, "locusOfFocus", target),
|
||||
mock.patch.object(
|
||||
AXUtilitiesEvent,
|
||||
"get_text_event_reason",
|
||||
return_value=TextEventReason.NAVIGATION_BY_CHARACTER,
|
||||
),
|
||||
mock.patch.object(web_script.AXUtilities, "is_editable", return_value=False),
|
||||
mock.patch.object(web_script.AXUtilities, "is_dialog_or_alert", return_value=False),
|
||||
mock.patch.object(web_script.AXUtilities, "is_focusable", return_value=True),
|
||||
mock.patch.object(web_script.AXUtilities, "is_focused", return_value=True),
|
||||
mock.patch.object(web_script.AXUtilities, "is_document", return_value=False),
|
||||
mock.patch.object(
|
||||
default.Script,
|
||||
"onCaretMoved",
|
||||
side_effect=lambda _script, _event: presentations.append("caret-event"),
|
||||
) as defaultCaretHandler,
|
||||
mock.patch.object(
|
||||
default.Script,
|
||||
"onFocusedChanged",
|
||||
side_effect=lambda _script, _event: presentations.append("focus-event"),
|
||||
) as defaultFocusHandler,
|
||||
):
|
||||
WebEventSequence(testScript).run(events)
|
||||
|
||||
self.assertEqual(presentations, ["navigation-command"])
|
||||
defaultCaretHandler.assert_not_called()
|
||||
defaultFocusHandler.assert_not_called()
|
||||
|
||||
def test_caret_navigation_owns_following_caret_and_focus_events(self) -> None:
|
||||
self._assert_navigation_command_owns_caret_and_focus_pair(
|
||||
caretNavigation=True,
|
||||
structuralNavigation=False,
|
||||
)
|
||||
|
||||
def test_structural_navigation_owns_following_caret_and_focus_events(self) -> None:
|
||||
self._assert_navigation_command_owns_caret_and_focus_pair(
|
||||
caretNavigation=False,
|
||||
structuralNavigation=True,
|
||||
)
|
||||
|
||||
def test_tab_clears_navigation_ownership_and_real_focus_still_presents(self) -> None:
|
||||
document = object()
|
||||
oldTarget = FakeAccessible(Atspi.Role.PARAGRAPH)
|
||||
newTarget = FakeAccessible(Atspi.Role.ENTRY, editable=True)
|
||||
testScript = self._make_script(document, oldTarget)
|
||||
testScript._lastCommandWasCaretNav = True
|
||||
ignoredFocus = FakeEvent(
|
||||
"object:state-changed:focused",
|
||||
oldTarget,
|
||||
detail1=1,
|
||||
)
|
||||
realFocus = FakeEvent(
|
||||
"object:state-changed:focused",
|
||||
newTarget,
|
||||
detail1=1,
|
||||
)
|
||||
tabEvent = mock.Mock(event_string="Tab")
|
||||
tabEvent.is_modifier_key.return_value = False
|
||||
presentations: list[FakeAccessible] = []
|
||||
|
||||
with (
|
||||
mock.patch.object(cthulhu_state, "locusOfFocus", oldTarget),
|
||||
mock.patch.object(
|
||||
web_script.AXUtilities,
|
||||
"is_editable",
|
||||
side_effect=lambda obj: obj.editable,
|
||||
),
|
||||
mock.patch.object(web_script.AXUtilities, "is_dialog_or_alert", return_value=False),
|
||||
mock.patch.object(web_script.AXUtilities, "is_focusable", return_value=True),
|
||||
mock.patch.object(web_script.AXUtilities, "is_focused", return_value=True),
|
||||
mock.patch.object(web_script.AXUtilities, "is_document", return_value=False),
|
||||
mock.patch.object(default.Script, "shouldConsumeKeyboardEvent", return_value=False),
|
||||
mock.patch.object(
|
||||
default.Script,
|
||||
"onFocusedChanged",
|
||||
side_effect=lambda _script, event: presentations.append(event.source),
|
||||
) as defaultFocusHandler,
|
||||
):
|
||||
WebEventSequence(testScript).run([ignoredFocus])
|
||||
web_script.Script.shouldConsumeKeyboardEvent(testScript, tabEvent, None)
|
||||
WebEventSequence(testScript).run([realFocus])
|
||||
|
||||
self.assertEqual(presentations, [newTarget])
|
||||
self.assertFalse(testScript._lastCommandWasCaretNav)
|
||||
self.assertFalse(testScript._lastCommandWasStructNav)
|
||||
defaultFocusHandler.assert_called_once_with(testScript, realFocus)
|
||||
|
||||
def _assert_document_focus_uses_recovered_context_once(
|
||||
self,
|
||||
*,
|
||||
pageNavigation: bool,
|
||||
documentFragment: str,
|
||||
) -> None:
|
||||
document = FakeAccessible(Atspi.Role.DOCUMENT_WEB)
|
||||
oldFocus = FakeAccessible(Atspi.Role.FRAME)
|
||||
context = FakeAccessible(Atspi.Role.LINK)
|
||||
testScript = self._make_script(document, context)
|
||||
testScript.utilities.getDocumentForObject.side_effect = (
|
||||
lambda obj: document if obj is document else None
|
||||
)
|
||||
testScript.utilities.getCaretContext.return_value = (None, -1)
|
||||
testScript.utilities.searchForCaretContext.return_value = (context, 6)
|
||||
testScript.utilities.lastInputEventWasPageNav.return_value = pageNavigation
|
||||
testScript.utilities.isLink.side_effect = lambda obj: obj is context
|
||||
testScript.utilities.documentFragment.return_value = documentFragment
|
||||
event = FakeEvent("object:state-changed:focused", document, detail1=1)
|
||||
presentations: list[FakeAccessible] = []
|
||||
|
||||
def set_focus(
|
||||
_event: FakeEvent,
|
||||
obj: FakeAccessible,
|
||||
notifyScript: bool = True,
|
||||
) -> None:
|
||||
if notifyScript:
|
||||
presentations.append(obj)
|
||||
|
||||
with (
|
||||
mock.patch.object(cthulhu_state, "locusOfFocus", oldFocus),
|
||||
mock.patch.object(web_script.AXUtilities, "is_editable", return_value=False),
|
||||
mock.patch.object(web_script.AXUtilities, "is_dialog_or_alert", return_value=False),
|
||||
mock.patch.object(web_script.AXUtilities, "is_focusable", return_value=True),
|
||||
mock.patch.object(
|
||||
web_script.AXUtilities,
|
||||
"is_focused",
|
||||
side_effect=lambda obj: obj is document,
|
||||
),
|
||||
mock.patch.object(
|
||||
web_script.AXUtilities,
|
||||
"is_document",
|
||||
side_effect=lambda obj: obj is document,
|
||||
),
|
||||
mock.patch.object(web_script.AXObject, "clear_cache"),
|
||||
mock.patch.object(web_script.cthulhu, "setLocusOfFocus", side_effect=set_focus) as setFocus,
|
||||
mock.patch.object(default.Script, "onFocusedChanged") as defaultFocusHandler,
|
||||
):
|
||||
WebEventSequence(testScript).run([event])
|
||||
|
||||
self.assertEqual(presentations, [context])
|
||||
self.assertEqual(
|
||||
setFocus.call_args_list,
|
||||
[mock.call(event, context, False), mock.call(event, context)],
|
||||
)
|
||||
testScript.utilities.setCaretContext.assert_has_calls(
|
||||
[mock.call(context, 6), mock.call(context, 6)]
|
||||
if pageNavigation
|
||||
else [mock.call(context, 6)]
|
||||
)
|
||||
defaultFocusHandler.assert_not_called()
|
||||
|
||||
def test_page_navigation_focus_uses_recovered_caret_context_once(self) -> None:
|
||||
self._assert_document_focus_uses_recovered_context_once(
|
||||
pageNavigation=True,
|
||||
documentFragment="",
|
||||
)
|
||||
|
||||
def test_page_fragment_focus_uses_recovered_caret_context_once(self) -> None:
|
||||
self._assert_document_focus_uses_recovered_context_once(
|
||||
pageNavigation=False,
|
||||
documentFragment="#details",
|
||||
)
|
||||
|
||||
|
||||
class ChromiumNativeContainerSequenceTests(unittest.TestCase):
|
||||
"""Current routing contracts for native containers in Chromium content."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user