mops 3.2.1__tar.gz → 3.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {mops-3.2.1 → mops-3.3.1}/PKG-INFO +1 -1
  2. {mops-3.2.1 → mops-3.3.1}/mops/__init__.py +1 -1
  3. {mops-3.2.1 → mops-3.3.1}/mops/abstraction/driver_wrapper_abc.py +15 -4
  4. {mops-3.2.1 → mops-3.3.1}/mops/abstraction/element_abc.py +17 -5
  5. {mops-3.2.1 → mops-3.3.1}/mops/base/driver_wrapper.py +16 -7
  6. {mops-3.2.1 → mops-3.3.1}/mops/base/element.py +74 -12
  7. {mops-3.2.1 → mops-3.3.1}/mops/js_scripts.py +1 -1
  8. mops-3.3.1/mops/mixins/capabilities.py +4 -0
  9. mops-3.3.1/mops/mixins/native_context.py +89 -0
  10. mops-3.3.1/mops/mixins/objects/visual_comaprison_mixin.py +34 -0
  11. {mops-3.2.1 → mops-3.3.1}/mops/playwright/play_driver.py +10 -4
  12. {mops-3.2.1 → mops-3.3.1}/mops/playwright/play_element.py +7 -37
  13. {mops-3.2.1 → mops-3.3.1}/mops/selenium/core/core_driver.py +10 -4
  14. {mops-3.2.1 → mops-3.3.1}/mops/selenium/core/core_element.py +40 -54
  15. {mops-3.2.1 → mops-3.3.1}/mops/selenium/elements/mobile_element.py +1 -1
  16. {mops-3.2.1 → mops-3.3.1}/mops/selenium/elements/web_element.py +7 -1
  17. {mops-3.2.1 → mops-3.3.1}/mops/utils/internal_utils.py +5 -8
  18. {mops-3.2.1 → mops-3.3.1}/mops/utils/selector_synchronizer.py +48 -23
  19. {mops-3.2.1 → mops-3.3.1}/mops/visual_comparison.py +21 -23
  20. {mops-3.2.1 → mops-3.3.1}/mops.egg-info/PKG-INFO +1 -1
  21. {mops-3.2.1 → mops-3.3.1}/mops.egg-info/SOURCES.txt +2 -0
  22. mops-3.2.1/mops/mixins/native_context.py +0 -56
  23. {mops-3.2.1 → mops-3.3.1}/README.md +0 -0
  24. {mops-3.2.1 → mops-3.3.1}/mops/abstraction/mixin_abc.py +0 -0
  25. {mops-3.2.1 → mops-3.3.1}/mops/abstraction/page_abc.py +0 -0
  26. {mops-3.2.1 → mops-3.3.1}/mops/base/group.py +0 -0
  27. {mops-3.2.1 → mops-3.3.1}/mops/base/page.py +0 -0
  28. {mops-3.2.1 → mops-3.3.1}/mops/exceptions.py +0 -0
  29. {mops-3.2.1 → mops-3.3.1}/mops/keyboard_keys.py +0 -0
  30. {mops-3.2.1 → mops-3.3.1}/mops/mixins/driver_mixin.py +0 -0
  31. {mops-3.2.1 → mops-3.3.1}/mops/mixins/internal_mixin.py +0 -0
  32. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/box.py +0 -0
  33. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/driver.py +0 -0
  34. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/location.py +0 -0
  35. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/locator.py +0 -0
  36. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/locator_type.py +0 -0
  37. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/scrolls.py +0 -0
  38. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/size.py +0 -0
  39. {mops-3.2.1 → mops-3.3.1}/mops/mixins/objects/wait_result.py +0 -0
  40. {mops-3.2.1 → mops-3.3.1}/mops/playwright/play_page.py +0 -0
  41. {mops-3.2.1 → mops-3.3.1}/mops/selenium/core/core_page.py +0 -0
  42. {mops-3.2.1 → mops-3.3.1}/mops/selenium/driver/mobile_driver.py +0 -0
  43. {mops-3.2.1 → mops-3.3.1}/mops/selenium/driver/web_driver.py +0 -0
  44. {mops-3.2.1 → mops-3.3.1}/mops/selenium/pages/mobile_page.py +0 -0
  45. {mops-3.2.1 → mops-3.3.1}/mops/selenium/pages/web_page.py +0 -0
  46. {mops-3.2.1 → mops-3.3.1}/mops/selenium/sel_utils.py +0 -0
  47. {mops-3.2.1 → mops-3.3.1}/mops/shared_utils.py +0 -0
  48. {mops-3.2.1 → mops-3.3.1}/mops/utils/decorators.py +0 -0
  49. {mops-3.2.1 → mops-3.3.1}/mops/utils/logs.py +0 -0
  50. {mops-3.2.1 → mops-3.3.1}/mops/utils/previous_object_driver.py +0 -0
  51. {mops-3.2.1 → mops-3.3.1}/mops.egg-info/dependency_links.txt +0 -0
  52. {mops-3.2.1 → mops-3.3.1}/mops.egg-info/requires.txt +0 -0
  53. {mops-3.2.1 → mops-3.3.1}/mops.egg-info/top_level.txt +0 -0
  54. {mops-3.2.1 → mops-3.3.1}/pyproject.toml +0 -0
  55. {mops-3.2.1 → mops-3.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mops
3
- Version: 3.2.1
3
+ Version: 3.3.1
4
4
  Summary: Wrapper of Selenium, Appium and Playwright with single API
5
5
  Author-email: Podolian Vladimir <vladimir.podolyan64@gmail.com>
6
6
  License: MIT
@@ -1,2 +1,2 @@
1
- __version__ = '3.2.1'
1
+ __version__ = '3.3.1'
2
2
  __project_name__ = 'mops'
@@ -95,13 +95,16 @@ class DriverWrapperABC(ABC):
95
95
  """
96
96
  raise NotImplementedError()
97
97
 
98
- def wait(self, timeout: Union[int, float] = WAIT_UNIT) -> DriverWrapper:
98
+ def wait(self, timeout: Union[int, float] = WAIT_UNIT, reason: str = '') -> DriverWrapper:
99
99
  """
100
100
  Pauses the execution for a specified amount of time.
101
101
 
102
102
  :param timeout: The time to sleep in seconds (can be an integer or float).
103
103
  :type timeout: typing.Union[int, float]
104
104
 
105
+ :param reason: The waiting reason.
106
+ :type reason: str
107
+
105
108
  :return: :obj:`.DriverWrapper` - The current instance of the driver wrapper.
106
109
  """
107
110
  raise NotImplementedError()
@@ -222,15 +225,15 @@ class DriverWrapperABC(ABC):
222
225
  """
223
226
  raise NotImplementedError()
224
227
 
225
- def execute_script(self, script: str, *args) -> Any:
228
+ def execute_script(self, script: str, *args: Any) -> Any:
226
229
  """
227
230
  Synchronously executes JavaScript in the current window or frame.
228
231
  Compatible with Selenium's `execute_script` method.
229
232
 
230
233
  :param script: The JavaScript code to execute.
231
234
  :type script: str
232
- :param args: Any arguments to pass to the JavaScript (e.g., Element object).
233
- :type args: list
235
+ :param args: Any arguments to pass to the JavaScript.
236
+ :type args: :obj:`typing.Any`
234
237
  :return: :obj:`typing.Any` - The result of the JavaScript execution.
235
238
  """
236
239
  raise NotImplementedError()
@@ -307,6 +310,14 @@ class DriverWrapperABC(ABC):
307
310
  """
308
311
  raise NotImplementedError()
309
312
 
313
+ def get_scroll_position(self) -> int:
314
+ """
315
+ Returns the current vertical scroll position of the page.
316
+
317
+ :return: :class:`int` - Current vertical scroll offset in pixels.
318
+ """
319
+ raise NotImplementedError()
320
+
310
321
  def assert_screenshot(
311
322
  self,
312
323
  filename: str = '',
@@ -258,22 +258,34 @@ class ElementABC(MixinABC, ABC):
258
258
  """
259
259
  raise NotImplementedError()
260
260
 
261
- def hide(self) -> Element:
261
+ def hide(self, silent: bool = False) -> Element:
262
262
  """
263
- Hides the element.
263
+ Make the element invisible by setting its opacity to 0.
264
264
 
265
+ :param silent: If :obj:`True`, suppresses logging.
266
+ :type silent: bool
267
+ :return: :class:`Element`
268
+ """
269
+ raise NotImplementedError()
270
+
271
+ def show(self, silent: bool = False) -> Element:
272
+ """
273
+ Make the element visible by setting its opacity to 1.
274
+
275
+ :param silent: If :obj:`True`, suppresses logging.
276
+ :type silent: bool
265
277
  :return: :class:`Element`
266
278
  """
267
279
  raise NotImplementedError()
268
280
 
269
- def execute_script(self, script: str, *args) -> Any:
281
+ def execute_script(self, script: str, *args: Any) -> Any:
270
282
  """
271
283
  Executes a JavaScript script on the element.
272
284
 
273
285
  :param script: JavaScript code to be executed, referring to the element as ``arguments[0]``.
274
286
  :type script: str
275
- :param args: Additional arguments for the script,
276
- that appear in script as ``arguments[1]`` ``arguments[2]`` etc.
287
+ :param args: Any arguments to pass to the JavaScript.
288
+ :type args: :obj:`typing.Any`
277
289
  :return: :obj:`typing.Any` result from the script.
278
290
  """
279
291
  raise NotImplementedError()
@@ -13,6 +13,7 @@ from playwright.sync_api import (
13
13
 
14
14
  from mops.mixins.objects.box import Box
15
15
  from mops.mixins.objects.driver import Driver
16
+ from mops.mixins.objects.visual_comaprison_mixin import hide_before_screenshot, reveal_after_screenshot
16
17
  from mops.visual_comparison import VisualComparison
17
18
  from mops.abstraction.driver_wrapper_abc import DriverWrapperABC
18
19
  from mops.playwright.play_driver import PlayDriver
@@ -220,6 +221,14 @@ class DriverWrapper(InternalMixin, Logging, DriverWrapperABC):
220
221
 
221
222
  return image_object
222
223
 
224
+ def get_scroll_position(self) -> int:
225
+ """
226
+ Returns the current vertical scroll position of the page.
227
+
228
+ :return: :class:`int` - Current vertical scroll offset in pixels.
229
+ """
230
+ return self.execute_script('return window.pageYOffset')
231
+
223
232
  def assert_screenshot(
224
233
  self,
225
234
  filename: str = '',
@@ -263,17 +272,17 @@ class DriverWrapper(InternalMixin, Logging, DriverWrapperABC):
263
272
  delay = delay or VisualComparison.default_delay
264
273
  remove = [remove] if type(remove) is not list and remove else remove
265
274
 
266
- if hide:
267
- if not isinstance(hide, list):
268
- hide = [hide]
269
- for object_to_hide in hide:
270
- object_to_hide.hide()
275
+ hide_before_screenshot(hide, is_optional=False, dw=self)
276
+ self.wait(delay)
277
+ hide_before_screenshot(VisualComparison.always_hide, is_optional=True, dw=self)
271
278
 
272
279
  VisualComparison(self).assert_screenshot(
273
- filename=filename, test_name=test_name, name_suffix=name_suffix, threshold=threshold, delay=delay,
274
- scroll=False, remove=remove, fill_background=False, cut_box=cut_box
280
+ filename=filename, test_name=test_name, name_suffix=name_suffix, threshold=threshold,
281
+ remove=remove, fill_background=False, cut_box=cut_box
275
282
  )
276
283
 
284
+ reveal_after_screenshot(VisualComparison.always_hide, dw=self)
285
+
277
286
  def soft_assert_screenshot(
278
287
  self,
279
288
  filename: str = '',
@@ -1,10 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import time
3
4
  from copy import copy
4
5
  from typing import Union, List, Type, Tuple, Optional, TYPE_CHECKING
5
6
 
6
7
  from PIL.Image import Image
7
8
 
9
+ from mops.mixins.objects.scrolls import ScrollTo, ScrollTypes, scroll_into_view_blocks
10
+ from mops.mixins.objects.visual_comaprison_mixin import hide_before_screenshot, reveal_after_screenshot
8
11
  from mops.mixins.objects.wait_result import Result
9
12
  from playwright.sync_api import Page as PlaywrightDriver
10
13
  from appium.webdriver.webdriver import WebDriver as AppiumDriver
@@ -696,6 +699,43 @@ class Element(DriverMixin, InternalMixin, Logging, ElementABC):
696
699
 
697
700
  return is_visible
698
701
 
702
+ def scroll_into_view(
703
+ self,
704
+ block: ScrollTo = ScrollTo.CENTER,
705
+ behavior: ScrollTypes = ScrollTypes.INSTANT,
706
+ sleep: Union[int, float] = 0,
707
+ silent: bool = False,
708
+ ) -> Element:
709
+ """
710
+ Scrolls the element into view using a JavaScript script.
711
+
712
+ :param block: The scrolling block alignment. One of the :class:`.ScrollTo` options.
713
+ :type block: ScrollTo
714
+ :param behavior: The scrolling behavior. One of the :class:`.ScrollTypes` options.
715
+ :type behavior: ScrollTypes
716
+ :param sleep: Delay in seconds after scrolling. Can be an integer or a float.
717
+ :type sleep: typing.Union[int, float]
718
+ :param silent: If :obj:`True`, suppresses logging.
719
+ :type silent: bool
720
+ :return: :class:`Element`
721
+ """
722
+ if not silent:
723
+ self.log(f'Scroll element "{self.name}" into view')
724
+
725
+ if block not in scroll_into_view_blocks:
726
+ message = f'Provide one of {scroll_into_view_blocks} option in `block` argument'
727
+ raise UnsuitableArgumentsException(message)
728
+
729
+ self.execute_script(
730
+ 'arguments[0].scrollIntoView({block: arguments[1], behavior: arguments[2]});',
731
+ block, behavior
732
+ )
733
+
734
+ if sleep:
735
+ time.sleep(sleep)
736
+
737
+ return self
738
+
699
739
  def save_screenshot(
700
740
  self,
701
741
  file_name: str,
@@ -726,23 +766,42 @@ class Element(DriverMixin, InternalMixin, Logging, ElementABC):
726
766
 
727
767
  return image_object
728
768
 
729
- def hide(self) -> Element:
769
+ def hide(self, silent: bool = False) -> Element:
730
770
  """
731
- Hides the element.
771
+ Make the element invisible by setting its opacity to 0.
732
772
 
773
+ :param silent: If :obj:`True`, suppresses logging.
774
+ :type silent: bool
733
775
  :return: :class:`Element`
734
776
  """
777
+ if not silent:
778
+ self.log(f'Hiding element "{self.name}"')
779
+
735
780
  self.execute_script('arguments[0].style.opacity = "0";')
736
781
  return self
737
782
 
738
- def execute_script(self, script: str, *args) -> Any:
783
+ def show(self, silent: bool = False) -> Element:
784
+ """
785
+ Make the element visible by setting its opacity to 1.
786
+
787
+ :param silent: If :obj:`True`, suppresses logging.
788
+ :type silent: bool
789
+ :return: :class:`Element`
790
+ """
791
+ if not silent:
792
+ self.log(f'Showing element "{self.name}"')
793
+
794
+ self.execute_script('arguments[0].style.opacity = "1";')
795
+ return self
796
+
797
+ def execute_script(self, script: str, *args: Any) -> Any:
739
798
  """
740
799
  Executes a JavaScript script on the element.
741
800
 
742
801
  :param script: JavaScript code to be executed, referring to the element as ``arguments[0]``.
743
802
  :type script: str
744
- :param args: Additional arguments for the script,
745
- that appear in script as ``arguments[1]`` ``arguments[2]`` etc.
803
+ :param args: Any arguments to pass to the JavaScript.
804
+ :type args: :obj:`typing.Any`
746
805
  :return: :obj:`typing.Any` result from the script.
747
806
  """
748
807
  return self.driver_wrapper.execute_script(script, *[self, *[arg for arg in args]])
@@ -797,17 +856,20 @@ class Element(DriverMixin, InternalMixin, Logging, ElementABC):
797
856
  delay = delay or VisualComparison.default_delay
798
857
  remove = [remove] if type(remove) is not list and remove else remove
799
858
 
800
- if hide:
801
- if not isinstance(hide, list):
802
- hide = [hide]
803
- for object_to_hide in hide:
804
- object_to_hide.hide()
859
+ if scroll:
860
+ self.scroll_into_view()
861
+
862
+ hide_before_screenshot(hide, is_optional=False, dw=self.driver_wrapper)
863
+ self.driver_wrapper.wait(delay)
864
+ hide_before_screenshot(VisualComparison.always_hide, is_optional=True, dw=self.driver_wrapper)
805
865
 
806
866
  VisualComparison(self.driver_wrapper, self).assert_screenshot(
807
- filename=filename, test_name=test_name, name_suffix=name_suffix, threshold=threshold, delay=delay,
808
- scroll=scroll, remove=remove, fill_background=fill_background, cut_box=cut_box
867
+ filename=filename, test_name=test_name, name_suffix=name_suffix, threshold=threshold,
868
+ remove=remove, fill_background=fill_background, cut_box=cut_box
809
869
  )
810
870
 
871
+ reveal_after_screenshot(VisualComparison.always_hide, dw=self.driver_wrapper)
872
+
811
873
  def soft_assert_screenshot(
812
874
  self,
813
875
  filename: str = '',
@@ -70,7 +70,7 @@ return appendElement(arguments[0]);
70
70
  """
71
71
 
72
72
 
73
- hide_caret_js_script = 'document.activeElement.blur();'
73
+ hide_caret_js_script = "arguments[0].style.caretColor = 'transparent';"
74
74
 
75
75
 
76
76
  add_driver_index_comment_js = """
@@ -0,0 +1,4 @@
1
+ CUSTOM_TOP_BAR_LOCATOR_CAPABILITY = 'mops:customTopBarLocator'
2
+ CUSTOM_BOTTOM_BAR_LOCATOR_CAPABILITY = 'mops:customBottomBarLocator'
3
+ CUSTOM_DONE_BUTTON_LOCATOR_CAPABILITY = 'mops:customDoneButtonLocator'
4
+ CUSTOM_DEVICE_NAME_CAPABILITY = 'mops:customDeviceName'
@@ -0,0 +1,89 @@
1
+ from mops.mixins.objects.locator import Locator
2
+ from mops.mixins.capabilities import (
3
+ CUSTOM_BOTTOM_BAR_LOCATOR_CAPABILITY,
4
+ CUSTOM_DONE_BUTTON_LOCATOR_CAPABILITY,
5
+ CUSTOM_TOP_BAR_LOCATOR_CAPABILITY,
6
+ )
7
+
8
+
9
+ class NativeContext:
10
+
11
+ def __init__(self, driver_wrapper):
12
+ self.driver_wrapper = driver_wrapper
13
+
14
+ def __enter__(self):
15
+ self.driver_wrapper.switch_to_native()
16
+
17
+ def __exit__(self, *args):
18
+ self.driver_wrapper.switch_to_web()
19
+
20
+
21
+ class NativeSafari:
22
+
23
+ ios_keyboard_hide_button = "//XCUIElementTypeButton[@name='Done']"
24
+
25
+ ios_18_bottom_bar_locator = (
26
+ '//*[@name="CapsuleViewController"]/XCUIElementTypeOther/'
27
+ 'XCUIElementTypeOther[1]/XCUIElementTypeOther[1]'
28
+ ) # `Tab Bar` at Safari settings
29
+ ios_26_bottom_bar_locator = (
30
+ '//*[@name="CapsuleViewController"]'
31
+ '/XCUIElementTypeOther[2]'
32
+ ) # `Compact` at Safari settings
33
+
34
+ ipados_top_bar_locator = (
35
+ '//XCUIElementTypeOther[@name="UnifiedBar?isStandaloneBar=true"]'
36
+ '/XCUIElementTypeOther[1]'
37
+ )
38
+ ios_mobile_top_bar_locator = (
39
+ '//*[contains(@name, "SafariWindow")]/XCUIElementTypeOther[1]'
40
+ '/XCUIElementTypeOther/XCUIElementTypeOther'
41
+ )
42
+
43
+ def __init__(self, driver_wrapper):
44
+ from mops.base.element import Element
45
+ self.driver_wrapper = driver_wrapper
46
+
47
+ self.custom_top_bar_locator = self.driver_wrapper.caps.get(CUSTOM_TOP_BAR_LOCATOR_CAPABILITY, '')
48
+ self.top_bar = Element(
49
+ Locator(
50
+ mobile=self.custom_top_bar_locator or self.ios_mobile_top_bar_locator,
51
+ tablet=self.custom_top_bar_locator or self.ipados_top_bar_locator
52
+ ),
53
+ name='safari top bar',
54
+ driver_wrapper=driver_wrapper
55
+ )
56
+
57
+ self.custom_bottom_bar_locator = self.driver_wrapper.caps.get(CUSTOM_BOTTOM_BAR_LOCATOR_CAPABILITY, '')
58
+ self.bottom_bar = Element(
59
+ self.custom_bottom_bar_locator or self.ios_18_bottom_bar_locator,
60
+ name='safari bottom bar',
61
+ driver_wrapper=driver_wrapper
62
+ )
63
+
64
+ self.custom_done_button_locator = self.driver_wrapper.caps.get(CUSTOM_DONE_BUTTON_LOCATOR_CAPABILITY, '')
65
+ self.keyboard_done_button = Element(
66
+ locator=self.custom_done_button_locator or self.ios_keyboard_hide_button,
67
+ name='keyboard Done button',
68
+ driver_wrapper=driver_wrapper
69
+ )
70
+
71
+ def get_bottom_bar_height(self) -> int:
72
+ """
73
+ Get iOS/iPadOS bottom bar height
74
+
75
+ :return: int
76
+ """
77
+ if self.driver_wrapper.is_tablet:
78
+ return 0 # iPad does not have bottom bar
79
+
80
+ if not self.custom_bottom_bar_locator:
81
+ ios_version = float(self.driver_wrapper.driver.caps.get('platformVersion', 18.2))
82
+
83
+ if ios_version >= 18.2:
84
+ self.bottom_bar.locator = self.ios_18_bottom_bar_locator
85
+ elif ios_version >= 26.0:
86
+ self.bottom_bar.locator = self.ios_26_bottom_bar_locator
87
+
88
+
89
+ return self.bottom_bar.size.height
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Union, Any, TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from mops.base.element import Element
7
+ from mops.base.driver_wrapper import DriverWrapper
8
+
9
+
10
+ def hide_elements(objects_to_hide: Union[list[Element], Element], is_optional: bool, dw: DriverWrapper):
11
+ for object_to_hide in objects_to_hide:
12
+
13
+ if is_optional:
14
+ object_to_hide = object_to_hide(dw)
15
+ if object_to_hide.is_displayed(silent=True):
16
+ object_to_hide.hide(silent=True)
17
+ else:
18
+ object_to_hide.hide(silent=True)
19
+
20
+
21
+
22
+ def hide_before_screenshot(objects_to_hide: Union[list, Any], is_optional: bool, dw: DriverWrapper = None):
23
+ if objects_to_hide:
24
+ if not isinstance(objects_to_hide, list):
25
+ objects_to_hide = [objects_to_hide]
26
+
27
+ hide_elements(objects_to_hide, is_optional=is_optional, dw=dw)
28
+
29
+
30
+ def reveal_after_screenshot(objects_to_reveal: Union[list, Any], dw: DriverWrapper):
31
+ for object_to_reveal in objects_to_reveal:
32
+ object_to_reveal = object_to_reveal(dw)
33
+ if object_to_reveal.is_displayed(silent=True):
34
+ object_to_reveal.show(silent=True)
@@ -66,15 +66,21 @@ class PlayDriver(Logging, DriverWrapperABC):
66
66
  """
67
67
  return self.browser_name.lower() == 'firefox'
68
68
 
69
- def wait(self, timeout: Union[int, float] = WAIT_UNIT) -> PlayDriver:
69
+ def wait(self, timeout: Union[int, float] = WAIT_UNIT, reason: str = '') -> PlayDriver:
70
70
  """
71
71
  Pauses the execution for a specified amount of time.
72
72
 
73
73
  :param timeout: The time to sleep in seconds (can be an integer or float).
74
74
  :type timeout: typing.Union[int, float]
75
75
 
76
+ :param reason: The waiting reason.
77
+ :type reason: str
78
+
76
79
  :return: :obj:`.PlayDriver` - The current instance of the driver wrapper.
77
80
  """
81
+ if reason:
82
+ self.log(reason)
83
+
78
84
  self.driver.wait_for_timeout(get_timeout_in_ms(timeout))
79
85
  return self
80
86
 
@@ -245,15 +251,15 @@ class PlayDriver(Logging, DriverWrapperABC):
245
251
  self.driver = self._base_driver
246
252
  return self
247
253
 
248
- def execute_script(self, script: str, *args) -> Any:
254
+ def execute_script(self, script: str, *args: Any) -> Any:
249
255
  """
250
256
  Synchronously executes JavaScript in the current window or frame.
251
257
  Compatible with Selenium's `execute_script` method.
252
258
 
253
259
  :param script: The JavaScript code to execute.
254
260
  :type script: str
255
- :param args: Any arguments to pass to the JavaScript (e.g., Element object).
256
- :type args: list
261
+ :param args: Any arguments to pass to the JavaScript.
262
+ :type args: :obj:`typing.Any`
257
263
  :return: :obj:`typing.Any` - The result of the JavaScript execution.
258
264
  """
259
265
  script = script.replace('return ', '')
@@ -1,13 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- import time
4
3
  from abc import ABC
5
4
  from typing import Union, List, Any
6
5
 
7
6
  from PIL.Image import Image
8
7
  from mops.keyboard_keys import KeyboardKeys
9
- from mops.mixins.objects.scrolls import ScrollTo, ScrollTypes
10
- from playwright.sync_api import TimeoutError as PlayTimeoutError, Error
8
+ from playwright.sync_api import Error
11
9
  from playwright.sync_api import Page as PlaywrightPage
12
10
  from playwright.sync_api import Locator, Page, Browser, BrowserContext
13
11
 
@@ -16,12 +14,10 @@ from mops.mixins.objects.location import Location
16
14
  from mops.utils.decorators import retry
17
15
  from mops.utils.selector_synchronizer import get_platform_locator, set_playwright_locator
18
16
  from mops.abstraction.element_abc import ElementABC
19
- from mops.exceptions import TimeoutException, InvalidSelectorException
17
+ from mops.exceptions import InvalidSelectorException
20
18
  from mops.utils.logs import Logging
21
19
  from mops.shared_utils import cut_log_data, get_image
22
20
  from mops.utils.internal_utils import (
23
- WAIT_EL,
24
- get_timeout_in_ms,
25
21
  calculate_coordinate_to_click,
26
22
  is_group,
27
23
  is_element,
@@ -105,7 +101,11 @@ class PlayElement(ElementABC, Logging, ABC):
105
101
  if force_wait:
106
102
  self.wait_visibility(silent=True)
107
103
 
108
- self._first_element.click(**kwargs)
104
+ if self.driver_wrapper.is_mobile_resolution:
105
+ self._first_element.tap(**kwargs)
106
+ else:
107
+ self._first_element.click(**kwargs)
108
+
109
109
  return self
110
110
 
111
111
  def click_outside(self, x: int = -5, y: int = -5) -> PlayElement:
@@ -244,36 +244,6 @@ class PlayElement(ElementABC, Logging, ABC):
244
244
 
245
245
  # Element state
246
246
 
247
- def scroll_into_view(
248
- self,
249
- block: ScrollTo = ScrollTo.CENTER,
250
- behavior: ScrollTypes = ScrollTypes.INSTANT,
251
- sleep: Union[int, float] = 0,
252
- silent: bool = False,
253
- ) -> PlayElement:
254
- """
255
- Scrolls the element into view using a JavaScript script.
256
-
257
- :param block: The scrolling block alignment. One of the :class:`.ScrollTo` options.
258
- :type block: ScrollTo
259
- :param behavior: The scrolling behavior. One of the :class:`.ScrollTypes` options.
260
- :type behavior: ScrollTypes
261
- :param sleep: Delay in seconds after scrolling. Can be an integer or a float.
262
- :type sleep: typing.Union[int, float]
263
- :param silent: If :obj:`True`, suppresses logging.
264
- :type silent: bool
265
- :return: :class:`PlayElement`
266
- """
267
- if not silent:
268
- self.log(f'Scroll element "{self.name}" into view')
269
-
270
- self._first_element.scroll_into_view_if_needed()
271
-
272
- if sleep:
273
- time.sleep(sleep)
274
-
275
- return self
276
-
277
247
  def screenshot_image(self, screenshot_base: bytes = None) -> Image:
278
248
  """
279
249
  Returns a :class:`PIL.Image.Image` object representing the screenshot of the web element.
@@ -89,15 +89,21 @@ class CoreDriver(Logging, DriverWrapperABC):
89
89
  """
90
90
  return Size(**self.driver.get_window_size())
91
91
 
92
- def wait(self, timeout: Union[int, float] = WAIT_UNIT) -> CoreDriver:
92
+ def wait(self, timeout: Union[int, float] = WAIT_UNIT, reason: str = '') -> CoreDriver:
93
93
  """
94
94
  Pauses the execution for a specified amount of time.
95
95
 
96
96
  :param timeout: The time to sleep in seconds (can be an integer or float).
97
97
  :type timeout: typing.Union[int, float]
98
98
 
99
+ :param reason: The waiting reason.
100
+ :type reason: str
101
+
99
102
  :return: :obj:`.CoreDriver` - The current instance of the driver wrapper.
100
103
  """
104
+ if reason:
105
+ self.log(reason)
106
+
101
107
  time.sleep(timeout)
102
108
  return self
103
109
 
@@ -285,15 +291,15 @@ class CoreDriver(Logging, DriverWrapperABC):
285
291
  self.driver.switch_to.default_content()
286
292
  return self
287
293
 
288
- def execute_script(self, script: str, *args) -> Any:
294
+ def execute_script(self, script: str, *args: Any) -> Any:
289
295
  """
290
296
  Synchronously executes JavaScript in the current window or frame.
291
297
  Compatible with Selenium's `execute_script` method.
292
298
 
293
299
  :param script: The JavaScript code to execute.
294
300
  :type script: str
295
- :param args: Any arguments to pass to the JavaScript (e.g., Element object).
296
- :type args: list
301
+ :param args: Any arguments to pass to the JavaScript.
302
+ :type args: :obj:`typing.Any`
297
303
  :return: :obj:`typing.Any` - The result of the JavaScript execution.
298
304
  """
299
305
  args = [getattr(arg, 'element', arg) for arg in args]