Skip to content

Commit f9e1630

Browse files
feat: Fix review comments
1 parent 596538c commit f9e1630

File tree

19 files changed

+181
-124
lines changed

19 files changed

+181
-124
lines changed

appium/options/flutter/base.py renamed to appium/options/flutter_integration/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
from typing import Dict
1919
from appium.options.common.automation_name_option import AUTOMATION_NAME
2020
from appium.options.common.base import AppiumOptions
21-
from appium.options.flutter.flutter_element_wait_timeout_option import FlutterElementWaitTimeOutOption
22-
from appium.options.flutter.flutter_enable_mock_camera_option import FlutterEnableMockCameraOption
23-
from appium.options.flutter.flutter_server_launch_timeout_option import FlutterServerLaunchTimeOutOption
24-
from appium.options.flutter.flutter_system_port_option import FlutterSystemPortOption
21+
from appium.options.flutter_integration.flutter_element_wait_timeout_option import FlutterElementWaitTimeOutOption
22+
from appium.options.flutter_integration.flutter_enable_mock_camera_option import FlutterEnableMockCameraOption
23+
from appium.options.flutter_integration.flutter_server_launch_timeout_option import FlutterServerLaunchTimeOutOption
24+
from appium.options.flutter_integration.flutter_system_port_option import FlutterSystemPortOption
2525

2626

2727
class FlutterOptions(

appium/options/flutter/flutter_element_wait_timeout_option.py renamed to appium/options/flutter_integration/flutter_element_wait_timeout_option.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
from typing import Optional
18+
from datetime import timedelta
19+
from typing import Optional, Union
1920
from appium.options.common.supports_capabilities import SupportsCapabilities
2021

2122

@@ -25,9 +26,26 @@
2526
class FlutterElementWaitTimeOutOption(SupportsCapabilities):
2627

2728
@property
28-
def flutter_element_wait_timeout(self) -> Optional[int]:
29+
def flutter_element_wait_timeout(self) -> Optional[timedelta]:
30+
"""
31+
Maximum timeout to wait for element for Flutter integration test
32+
33+
Returns:
34+
Optional[timedelta]: The timeout value as a `timedelta` object if set, or `None` if the timeout is not defined.
35+
"""
2936
return self.get_capability(FLUTTER_ELEMENT_WAIT_TIMEOUT)
3037

3138
@flutter_element_wait_timeout.setter
32-
def flutter_element_wait_timeout(self, time_in_millis: int) -> None:
33-
self.set_capability(FLUTTER_ELEMENT_WAIT_TIMEOUT, time_in_millis)
39+
def flutter_element_wait_timeout(self, value: Union[timedelta, int]) -> None:
40+
"""
41+
Sets the maximum timeout to wait for a Flutter element in an integration test.
42+
Default timeout is 5000ms
43+
44+
Args:
45+
value (Union[timedelta, int]): The timeout value, either as a `timedelta` object or an integer in milliseconds.
46+
If provided as a `timedelta`, it will be converted to milliseconds.
47+
"""
48+
self.set_capability(
49+
FLUTTER_ELEMENT_WAIT_TIMEOUT,
50+
int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
51+
)

appium/options/flutter/flutter_enable_mock_camera_option.py renamed to appium/options/flutter_integration/flutter_enable_mock_camera_option.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,22 @@
2525
class FlutterEnableMockCameraOption(SupportsCapabilities):
2626

2727
@property
28-
def flutter_enable_mock_camera(self) -> Optional[int]:
28+
def flutter_enable_mock_camera(self) -> bool:
29+
"""
30+
Get state of the mock camera for Flutter integration test
31+
32+
Returns:
33+
bool: A boolean indicating whether the mock camera is enabled (True) or disabled (False).
34+
"""
2935
return self.get_capability(FLUTTER_ENABLE_MOCK_CAMERA)
3036

3137
@flutter_enable_mock_camera.setter
3238
def flutter_enable_mock_camera(self, value: bool) -> None:
39+
"""
40+
Setter method enable or disable the mock camera for Flutter integration test
41+
Default state is `False`
42+
43+
Args:
44+
value (bool): A boolean value indicating whether to enable (True) or disable (False) the mock camera.
45+
"""
3346
self.set_capability(FLUTTER_ENABLE_MOCK_CAMERA, value)

appium/options/flutter/flutter_server_launch_timeout_option.py renamed to appium/options/flutter_integration/flutter_server_launch_timeout_option.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
from typing import Optional
18+
from datetime import timedelta
19+
from typing import Optional, Union
1920
from appium.options.common.supports_capabilities import SupportsCapabilities
2021

2122

@@ -25,9 +26,27 @@
2526
class FlutterServerLaunchTimeOutOption(SupportsCapabilities):
2627

2728
@property
28-
def flutter_server_launch_timeout(self) -> Optional[int]:
29+
def flutter_server_launch_timeout(self) -> Optional[timedelta]:
30+
"""
31+
Gets the current timeout for launching the Flutter server in a Flutter application.
32+
33+
Returns:
34+
Optional[timedelta]: The timeout value as a `timedelta` object if set, or `None` if the timeout is not defined.
35+
36+
"""
2937
return self.get_capability(FLUTTER_SERVER_LAUNCH_TIMEOUT)
3038

3139
@flutter_server_launch_timeout.setter
32-
def flutter_server_launch_timeout(self, time_in_millis: int) -> None:
33-
self.set_capability(FLUTTER_SERVER_LAUNCH_TIMEOUT, time_in_millis)
40+
def flutter_server_launch_timeout(self, value: Union[timedelta, int]) -> None:
41+
"""
42+
Sets the timeout for launching the Flutter server in Flutter application.
43+
Default timeout is 5000ms
44+
45+
Args:
46+
value (Union[timedelta, int]): The timeout value, either as a `timedelta` object or an integer in milliseconds.
47+
If provided as a `timedelta`, it will be converted to milliseconds.
48+
"""
49+
self.set_capability(
50+
FLUTTER_SERVER_LAUNCH_TIMEOUT,
51+
int(value.total_seconds() * 1000) if isinstance(value, timedelta) else value
52+
)

appium/options/flutter/flutter_system_port_option.py renamed to appium/options/flutter_integration/flutter_system_port_option.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,21 @@ class FlutterSystemPortOption(SupportsCapabilities):
2626

2727
@property
2828
def flutter_system_port(self) -> Optional[int]:
29+
"""
30+
Get flutter system port for Flutter integration tests.
31+
32+
Returns:
33+
int: returns the port number
34+
"""
2935
return self.get_capability(FLUTTER_SYSTEM_PORT)
3036

3137
@flutter_system_port.setter
3238
def flutter_system_port(self, value: int) -> None:
39+
"""
40+
Sets the system port for Flutter integration tests.
41+
By default the first free port from 10000..11000 range is selected
42+
43+
Args:
44+
value (int): The port number to be used for the Flutter server.
45+
"""
3346
self.set_capability(FLUTTER_SYSTEM_PORT, value)

appium/webdriver/common/appiumby.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ class AppiumBy(By):
2525
ACCESSIBILITY_ID = 'accessibility id'
2626
IMAGE = '-image'
2727
CUSTOM = '-custom'
28+
FLUTTER_INTEGRATION_SEMANTICS_LABEL = '-flutter semantics label'
29+
FLUTTER_INTEGRATION_TYPE = '-flutter type'
30+
FLUTTER_INTEGRATION_KEY = '-flutter key'
31+
FLUTTER_INTEGRATION_TEXT = '-flutter text'
32+
FLUTTER_INTEGRATION_TEXT_CONTAINING = '-flutter text containing'

appium/webdriver/common/flutterby.py

Lines changed: 0 additions & 25 deletions
This file was deleted.

appium/webdriver/extensions/flutter/flutter_commands.py renamed to appium/webdriver/extensions/flutter_integration/flutter_commands.py

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,28 @@
1313
# limitations under the License.
1414

1515
import base64
16+
import os
1617
from typing import Any, Optional, Tuple, Union
18+
from appium.webdriver.extensions.flutter_integration.scroll_directions import ScrollDirection
1719
from appium.webdriver.flutter_finder import FlutterFinder
1820
from appium.webdriver.webdriver import WebDriver
1921
from appium.webdriver.webelement import WebElement
2022

2123

22-
class FlutterCommand():
24+
class FlutterCommand:
2325

2426
def __init__(self, driver: WebDriver) -> None:
2527
self.driver = driver
2628

2729
# wait commands
2830

29-
def wait_for_visible(self, locator: Union[WebElement, FlutterFinder], time_out: Optional[int] = None) -> None:
31+
def wait_for_visible(self, locator: Union[WebElement, FlutterFinder], time_out: Optional[float] = None) -> None:
3032
"""
3133
Waits for a element to become visible.
3234
3335
Args:
34-
locator: The element to wait for; can be a WebElement or a FlutterFinder.
35-
time_out: Maximum wait time in seconds. Defaults to a predefined timeout if not specified.
36+
locator (Union[WebElement, FlutterFinder]): The element to wait for; can be a WebElement or a FlutterFinder.
37+
time_out (Optional[float]): Maximum wait time in seconds. Defaults to a predefined timeout if not specified.
3638
3739
Returns:
3840
None:
@@ -45,13 +47,13 @@ def wait_for_visible(self, locator: Union[WebElement, FlutterFinder], time_out:
4547
self.execute_flutter_command('waitForVisible', opts)
4648

4749

48-
def wait_for_invisible(self, locator: Union[WebElement, FlutterFinder], time_out: Optional[int] = None) -> None:
50+
def wait_for_invisible(self, locator: Union[WebElement, FlutterFinder], time_out: Optional[float] = None) -> None:
4951
"""
5052
Waits for a element to become invisible.
5153
5254
Args:
53-
locator: The element to wait for; can be a WebElement or a FlutterFinder.
54-
time_out: Maximum wait time in seconds. Defaults to a predefined timeout if not specified.
55+
locator (Union[WebElement, FlutterFinder]): The element to wait for; can be a WebElement or a FlutterFinder.
56+
time_out (Optional[float]): Maximum wait time in seconds. Defaults to a predefined timeout if not specified.
5557
5658
Returns:
5759
None:
@@ -70,14 +72,14 @@ def perform_double_click(self, element: WebElement, offset: Optional[Tuple[int,
7072
Performs a double-click on the given element, with an optional offset.
7173
7274
Args:
73-
element: The element to double-click on. This parameter is required.
74-
offset: The x and y offsets from the element to click at. If not specified, the click is performed at the element's center.
75+
element (WebElement): The element to double-click on. This parameter is required.
76+
offset (Optional[Tuple[int, int]]): The x and y offsets from the element to click at. If not specified, the click is performed at the element's center.
7577
7678
Returns:
7779
None:
7880
"""
7981
opts = {'origin': element}
80-
if offset:
82+
if offset is not None:
8183
opts['offset'] = {'x': offset[0], 'y': offset[1]}
8284
self.execute_flutter_command('doubleClick', opts)
8385

@@ -86,14 +88,14 @@ def perform_long_press(self, element: WebElement, offset: Optional[Tuple[int, in
8688
Performs a long press on the given element, with an optional offset.
8789
8890
Args:
89-
element: The element to perform the long press on. This parameter is required.
90-
offset: The x and y offsets from the element to perform the long press at. If not specified, the long press is performed at the element's center.
91+
element (WebElement): The element to perform the long press on. This parameter is required.
92+
offset (Optional[Tuple[int, int]]): The x and y offsets from the element to perform the long press at. If not specified, the long press is performed at the element's center.
9193
9294
Returns:
9395
None:
9496
"""
9597
opts = {'origin': element}
96-
if offset:
98+
if offset is not None:
9799
opts['offset'] = {'x': offset[0], 'y': offset[1]}
98100
self.execute_flutter_command('longPress', opts)
99101

@@ -102,21 +104,21 @@ def perform_drag_and_drop(self, source: WebElement, target: WebElement) -> None:
102104
Performs a drag-and-drop operation from a source element to a target element.
103105
104106
Args:
105-
source: The element to drag from.
106-
target: The element to drop onto.
107+
source (WebElement): The element to drag from.
108+
target (WebElement): The element to drop onto.
107109
108110
Returns:
109111
None:
110112
"""
111113
self.execute_flutter_command('dragAndDrop', {'source': source, 'target': target})
112114

113-
def scroll_till_visible(self, scroll_to: FlutterFinder, scroll_direction: Optional[str] = 'down', **opts: Any) -> WebElement:
115+
def scroll_till_visible(self, scroll_to: FlutterFinder, scroll_direction: Optional[ScrollDirection] = ScrollDirection.DOWN, **opts: Any) -> WebElement:
114116
"""
115117
Scrolls until the specified element becomes visible.
116118
117119
Args:
118-
scroll_to: The Flutter element to scroll to.
119-
scroll_direction: The direction to scroll up/down. Defaults to 'down'.
120+
scroll_to (FlutterFinder): The Flutter element to scroll to.
121+
scroll_direction (Optional[ScrollDirection]): The direction to scroll up or down. Defaults to `ScrollDirection.DOWN`.
120122
121123
KeywordArgs:
122124
scrollView (str): The view of the scroll.
@@ -129,22 +131,21 @@ def scroll_till_visible(self, scroll_to: FlutterFinder, scroll_direction: Option
129131
Webelement: scrolled element
130132
"""
131133
opts['finder'] = scroll_to.to_dict()
132-
opts['scrollDirection'] = scroll_direction
134+
opts['scrollDirection'] = scroll_direction.as_string()
133135
return self.execute_flutter_command('scrollTillVisible', opts)
134136

135137
def inject_mock_image(self, value: str) -> str:
136138
"""
137139
Injects a mock image to the device. The input can be a file path or a base64-encoded string.
138140
139141
Args:
140-
value: The file path of the image or a base64-encoded string.
142+
value (str): The file path of the image or a base64-encoded string.
141143
142144
Returns:
143145
str: Image ID of the injected image.
144146
"""
145-
import os
146147
if os.path.isfile(value):
147-
with open(value, "rb") as image_file:
148+
with open(value, 'rb') as image_file:
148149
base64_encoded_image = base64.b64encode(image_file.read()).decode('utf-8')
149150
else:
150151
base64_encoded_image = value
@@ -155,12 +156,24 @@ def activate_injected_image(self, image_id: str) -> None:
155156
Activates an injected image with image ID.
156157
157158
Args:
158-
image_id: The ID of the injected image to activate.
159+
image_id (str): The ID of the injected image to activate.
159160
160161
Returns:
161162
None:
162163
"""
163-
self.execute_flutter_command("activateInjectedImage", {'imageId': image_id})
164+
self.execute_flutter_command('activateInjectedImage', {'imageId': image_id})
164165

165166
def execute_flutter_command(self, scriptName: str, params: dict) -> Any:
167+
"""
168+
Executes a Flutter command by sending a script and parameters to the flutter integration driver.
169+
170+
Args:
171+
scriptName (str): The name of the Flutter command to execute.
172+
This will be prefixed with 'flutter:' when passed to the driver.
173+
params (dict): A dictionary of parameters to be passed along with the Flutter command.
174+
175+
Returns:
176+
Any: The result of the command execution. The return value depends on the
177+
specific Flutter command being executed.
178+
"""
166179
return self.driver.execute_script(f'flutter: {scriptName}', params)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from enum import Enum
2+
3+
class ScrollDirection(Enum):
4+
UP = 'up'
5+
DOWN = 'down'
6+
7+
def as_string(self):
8+
return str(self.value)

0 commit comments

Comments
 (0)