1+ #!/usr/bin/env python3
2+ # -*- coding: utf-8 -*-
3+
4+ """Tests for input method functionality"""
5+
6+ from unittest .mock import Mock , patch
7+
8+ import pytest
9+
10+ from uiautomator2 ._input import InputMethodMixIn
11+ from uiautomator2 .exceptions import AdbBroadcastError
12+
13+
14+ class MockInputMethodMixIn (InputMethodMixIn ):
15+ """Mock implementation for testing"""
16+
17+ def __init__ (self ):
18+ self ._adb_device = Mock ()
19+ self ._jsonrpc = Mock ()
20+ self ._broadcast_calls = []
21+ self ._shell_calls = []
22+ self ._current_ime = 'com.github.uiautomator/.AdbKeyboard'
23+
24+ @property
25+ def adb_device (self ):
26+ return self ._adb_device
27+
28+ @property
29+ def jsonrpc (self ):
30+ return self ._jsonrpc
31+
32+ def shell (self , args ):
33+ """Mock shell method"""
34+ self ._shell_calls .append (args )
35+ result = Mock ()
36+ result .output = self ._current_ime
37+ return result
38+
39+ def _broadcast (self , action , extras = None ):
40+ """Mock broadcast method"""
41+ from uiautomator2 ._input import BORADCAST_RESULT_OK , BroadcastResult
42+ self ._broadcast_calls .append ((action , extras or {}))
43+ return BroadcastResult (BORADCAST_RESULT_OK , "success" )
44+
45+ def __call__ (self , ** kwargs ):
46+ """Mock selector call for fallback"""
47+ if not hasattr (self , '_mock_element' ):
48+ self ._mock_element = Mock ()
49+ self ._mock_element .set_text = Mock (return_value = True )
50+ return self ._mock_element
51+
52+
53+ def test_send_keys_hides_keyboard_when_using_custom_ime ():
54+ """Test that send_keys hides keyboard after successful input with custom IME"""
55+ mock_input = MockInputMethodMixIn ()
56+
57+ # Test successful send_keys with custom IME
58+ result = mock_input .send_keys ("hello world" )
59+
60+ # Should return True for successful operation
61+ assert result is True
62+
63+ # Check broadcast calls - should have both input and hide calls
64+ broadcast_calls = mock_input ._broadcast_calls
65+ assert len (broadcast_calls ) >= 2
66+
67+ # First call should be for input
68+ assert broadcast_calls [0 ][0 ] == "ADB_KEYBOARD_INPUT_TEXT"
69+ assert "text" in broadcast_calls [0 ][1 ]
70+
71+ # Last call should be for hiding keyboard
72+ assert broadcast_calls [- 1 ][0 ] == "ADB_KEYBOARD_HIDE"
73+ assert broadcast_calls [- 1 ][1 ] == {}
74+
75+
76+ def test_send_keys_fallback_does_not_hide_keyboard ():
77+ """Test that send_keys fallback to set_text does not hide keyboard"""
78+ mock_input = MockInputMethodMixIn ()
79+
80+ # Mock the _must_broadcast to raise AdbBroadcastError for input text
81+ def failing_must_broadcast (action , extras = None ):
82+ if action == "ADB_KEYBOARD_INPUT_TEXT" :
83+ raise AdbBroadcastError ("Simulated failure for input text" )
84+ # Should not reach here (keyboard hide) in fallback mode
85+ raise AdbBroadcastError (f"Unexpected broadcast call: { action } " )
86+
87+ mock_input ._must_broadcast = failing_must_broadcast
88+
89+ # Test fallback behavior
90+ with patch ('warnings.warn' ): # Suppress warning output
91+ result = mock_input .send_keys ("hello world" )
92+
93+ # Should return the result from set_text (True in our mock)
94+ assert result is True
95+
96+ # The element's set_text should have been called
97+ mock_element = mock_input (focused = True )
98+ assert mock_element .set_text .called
99+ mock_element .set_text .assert_called_with ("hello world" )
100+
101+
102+ def test_hide_keyboard_method ():
103+ """Test the hide_keyboard method directly"""
104+ mock_input = MockInputMethodMixIn ()
105+
106+ mock_input .hide_keyboard ()
107+
108+ # Should have made broadcast call for hiding
109+ broadcast_calls = mock_input ._broadcast_calls
110+ assert len (broadcast_calls ) >= 1
111+ assert broadcast_calls [- 1 ][0 ] == "ADB_KEYBOARD_HIDE"
112+ assert broadcast_calls [- 1 ][1 ] == {}
0 commit comments