Skip to content
This repository was archived by the owner on Aug 10, 2022. It is now read-only.

Commit 35c083d

Browse files
authored
Merge pull request #30 from applitools/feautre-fixed-cut-provider
Feautre fixed cut provider
2 parents 5d87639 + 3848c23 commit 35c083d

File tree

16 files changed

+193
-70
lines changed

16 files changed

+193
-70
lines changed

eyes_core/applitools/core/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
"PositionMomento",
4848
"InvalidPositionProvider",
4949
"RegionProvider",
50+
"FixedCutProvider",
51+
"NullCutProvider",
52+
"UnscaledFixedCutProvider",
5053
"NullRegionProvider",
5154
"NULL_REGION_PROVIDER",
5255
"CheckSettings",

eyes_core/applitools/core/eyes_base.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
from applitools.common.utils import ABC, argument_guard, general_utils
2626
from applitools.common.visual_grid import RenderingInfo
2727
from applitools.core.capture import AppOutputProvider, AppOutputWithScreenshot
28-
from applitools.core.cut import NullCutProvider
28+
from applitools.core.cut import (
29+
NullCutProvider,
30+
FixedCutProvider,
31+
UnscaledFixedCutProvider,
32+
)
2933
from applitools.core.debug import (
3034
FileDebugScreenshotProvider,
3135
NullDebugScreenshotProvider,
@@ -40,7 +44,7 @@
4044
from applitools.common.utils.custom_types import ViewPort, UserInputs, Num
4145
from applitools.core.fluent.check_settings import CheckSettings
4246
from applitools.common.capture import EyesScreenshot
43-
from typing import Optional, Text
47+
from typing import Optional, Text, Union
4448

4549
__all__ = ("EyesBase",)
4650

@@ -172,8 +176,17 @@ def debug_screenshot_provider(self):
172176

173177
@property
174178
def cut_provider(self):
179+
# type: () -> Union[FixedCutProvider, UnscaledFixedCutProvider, NullCutProvider]
175180
return self._cut_provider
176181

182+
@cut_provider.setter
183+
def cut_provider(self, provider):
184+
# type: (Union[FixedCutProvider, UnscaledFixedCutProvider, NullCutProvider]) -> None
185+
argument_guard.is_in(
186+
provider, [FixedCutProvider, UnscaledFixedCutProvider, NullCutProvider]
187+
)
188+
self._cut_provider = provider
189+
177190
@property
178191
def is_debug_screenshot_provided(self):
179192
# type: () -> bool
@@ -182,6 +195,7 @@ def is_debug_screenshot_provided(self):
182195

183196
@is_debug_screenshot_provided.setter
184197
def is_debug_screenshot_provided(self, save):
198+
# type: (bool) -> None
185199
prev = self._debug_screenshot_provider
186200
if save:
187201
self._debug_screenshot_provider = FileDebugScreenshotProvider(
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
from applitools.common import BatchInfo, MatchLevel, Region, logger
2+
from applitools.core.cut import (
3+
FixedCutProvider,
4+
UnscaledFixedCutProvider,
5+
NullCutProvider,
6+
)
27
from applitools.images.fluent import Target
38

49
from .eyes import Eyes
510

6-
__all__ = ("Eyes", "BatchInfo", "Region", "MatchLevel", "logger", "Target")
11+
__all__ = (
12+
"Eyes",
13+
"BatchInfo",
14+
"Region",
15+
"MatchLevel",
16+
"logger",
17+
"Target",
18+
"FixedCutProvider",
19+
"UnscaledFixedCutProvider",
20+
"NullCutProvider",
21+
)

eyes_images/applitools/images/eyes.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
from applitools.common import Configuration, EyesError, RectangleSize, Region, logger
44
from applitools.common.utils.general_utils import proxy_to
5-
from applitools.core import NULL_REGION_PROVIDER, EyesBase, RegionProvider
5+
from applitools.core import (
6+
NULL_REGION_PROVIDER,
7+
EyesBase,
8+
RegionProvider,
9+
NullCutProvider,
10+
)
611
from applitools.images.fluent import ImagesCheckSettings, Target
712

813
from .__version__ import __version__
@@ -125,7 +130,11 @@ def _check_image(self, region_provider, name, ignore_mismatch, check_settings):
125130
raise EyesError("you must call open() before checking")
126131

127132
image = check_settings.values.image # type: Image.Image
128-
# TODO: Add cut provider
133+
134+
if not isinstance(self.cut_provider, NullCutProvider):
135+
logger.debug("cutting...")
136+
image = self.cut_provider.cut(image)
137+
self.debug_screenshot_provider.save(image, "cut")
129138

130139
self._screenshot = EyesImagesScreenshot(image)
131140
if not self.configuration.viewport_size:

eyes_selenium/applitools/selenium/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
ScreenOrientation,
1212
)
1313
from applitools.common.server import FailureReports # noqa
14+
from applitools.core.cut import (
15+
NullCutProvider,
16+
FixedCutProvider,
17+
UnscaledFixedCutProvider,
18+
) # noqa
1419

1520
from .eyes import Eyes # noqa
1621
from .fluent.target import Target # noqa
@@ -34,4 +39,7 @@
3439
"DeviceName",
3540
"Configuration",
3641
"ScreenOrientation",
42+
"FixedCutProvider",
43+
"NullCutProvider",
44+
"UnscaledFixedCutProvider",
3745
)

eyes_selenium/applitools/selenium/eyes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Eyes(object):
3434
"device_pixel_ratio",
3535
"scale_ratio",
3636
"position_provider",
37+
"cut_provider",
3738
"_original_frame_chain",
3839
"full_agent_id",
3940
"agent_setup",

eyes_selenium/applitools/selenium/eyes_selenium_utils.py

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -100,46 +100,43 @@
100100
_RETRIES = 3
101101

102102

103-
def is_mobile_device(driver):
103+
def is_mobile_platform(driver):
104104
# type: (AnyWebDriver) -> bool
105105
"""
106-
Returns whether the platform running is a mobile device or not.
107-
108-
:return: True if the platform running the test is a mobile platform. False otherwise.
109-
"""
110-
is_mobile = """
111-
if( navigator.userAgent.match(/Android/i) ||
112-
navigator.userAgent.match(/iPhone/i) ||
113-
navigator.userAgent.match(/iPad/i) ||
114-
navigator.userAgent.match(/iPod/i) ) {
115-
return true;
116-
} else {
117-
return false;
118-
}
106+
Returns whether the platform running is a mobile browser or app.
119107
"""
120-
# TODO: Implement proper UserAgent handling
121108
driver = get_underlying_driver(driver)
122109
if isinstance(driver, AppiumWebDriver):
123110
return True
111+
return is_mobile_web(driver) or is_mobile_app(driver)
112+
124113

114+
def is_mobile_web(driver):
115+
# type: (AnyWebDriver) -> bool
116+
"""
117+
Returns whether the platform running is a mobile browser.
118+
"""
125119
# if driver is selenium based
126120
platform_name = driver.desired_capabilities.get("platformName", "").lower()
127-
# platformName sometime have different names
128-
is_mobile_platform = "android" in platform_name or "ios" in platform_name
129-
if not is_mobile_platform:
130-
try:
131-
is_mobile_platform = driver.execute_script(is_mobile)
132-
except WebDriverException as e:
133-
logger.warning(
134-
"Got error during checking if current platform is mobile. "
135-
"\n\t {}".format(str(e))
136-
)
137-
if "Method is not implemented" in str(e):
138-
# potentially mobile app
139-
is_mobile_platform = True
140-
else:
141-
is_mobile_platform = False
142-
return is_mobile_platform
121+
browser_name = driver.desired_capabilities.get("browserName", "").lower()
122+
is_mobile = "android" in platform_name or "ios" in platform_name
123+
if is_mobile and browser_name:
124+
return True
125+
return False
126+
127+
128+
def is_mobile_app(driver):
129+
# type: (AnyWebDriver) -> bool
130+
"""
131+
Returns whether the platform running is a mobile app.
132+
"""
133+
platform_name = driver.desired_capabilities.get("platformName", "").lower()
134+
browser_name = driver.desired_capabilities.get("browserName", "").lower()
135+
app = driver.desired_capabilities.get("app", None)
136+
is_mobile = "android" in platform_name or "ios" in platform_name
137+
if is_mobile and app and not browser_name:
138+
return True
139+
return False
143140

144141

145142
def get_underlying_driver(driver):
@@ -210,7 +207,7 @@ def set_browser_size(driver, required_size):
210207
retries_left = _RETRIES
211208

212209
# set browser size for mobile devices isn't working
213-
if is_mobile_device(driver):
210+
if is_mobile_web(driver):
214211
return True
215212

216213
while True:
@@ -380,7 +377,7 @@ def timeout(timeout):
380377

381378

382379
def is_landscape_orientation(driver):
383-
if is_mobile_device(driver):
380+
if is_mobile_web(driver):
384381
# could be AppiumRemoteWebDriver
385382
appium_driver = get_underlying_driver(
386383
driver
@@ -453,7 +450,7 @@ def root_html():
453450
return driver.find_element_by_tag_name("html")
454451

455452
scroll_root_element = None
456-
if not driver.is_mobile_device():
453+
if not driver.is_mobile_app:
457454
if container is None:
458455
scroll_root_element = root_html()
459456
else:
@@ -479,6 +476,6 @@ def current_frame_scroll_root_element(driver):
479476
root_element = None
480477
if cur_frame:
481478
root_element = cur_frame.scroll_root_element
482-
if root_element is None and not driver.is_mobile_device():
479+
if root_element is None and not driver.is_mobile_app:
483480
root_element = driver.find_element_by_tag_name("html")
484481
return root_element

eyes_selenium/applitools/selenium/positioning.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def __init__(self, driver, scroll_root_element):
5050

5151
def __enter__(self):
5252
# type: () -> SeleniumPositionProvider
53-
if self._driver.is_mobile_device():
53+
if self._driver.is_mobile_app:
5454
return self
5555
return super(SeleniumPositionProvider, self).__enter__()
5656

@@ -61,7 +61,7 @@ def __exit__(
6161
exc_tb, # type: Optional[Any]
6262
):
6363
# type: (...) -> Union[CSSTranslatePositionProvider, ScrollPositionProvider]
64-
if self._driver.is_mobile_device():
64+
if self._driver.is_mobile_app:
6565
return self
6666
return super(SeleniumPositionProvider, self).__exit__(exc_type, exc_val, exc_tb)
6767

@@ -71,7 +71,7 @@ def get_entire_size(self):
7171
:return: The entire size of the container which the position is relative to.
7272
"""
7373
try:
74-
if self._driver.is_mobile_device():
74+
if self._driver.is_mobile_app:
7575
width, height = self._driver.execute_script(
7676
self._JS_GET_CONTENT_ENTIRE_SIZE
7777
)
@@ -108,7 +108,7 @@ def set_position(self, location):
108108
logger.debug(
109109
"setting position of %s to %s" % (location, self._scroll_root_element)
110110
)
111-
if self._driver.is_mobile_device():
111+
if self._driver.is_mobile_web:
112112
scroll_command = "window.scrollTo({0}, {1})".format(location.x, location.y)
113113
self._driver.execute_script(scroll_command)
114114
self._last_set_position = location
@@ -139,7 +139,7 @@ def get_current_position(self):
139139
"""
140140
The scroll position of the current frame.
141141
"""
142-
if self._driver.is_mobile_device():
142+
if self._driver.is_mobile_web:
143143
x, y = self._driver.execute_script(
144144
self._JS_GET_CURRENT_SCROLL_POSITION, self._scroll_root_element
145145
)

eyes_selenium/applitools/selenium/selenium_eyes.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
PositionProvider,
2828
RegionProvider,
2929
TextTrigger,
30+
NullCutProvider,
3031
)
3132
from applitools.selenium.capture.eyes_webdriver_screenshot import (
3233
EyesWebDriverScreenshotFactory,
@@ -242,7 +243,7 @@ def check(self, name, check_settings=None):
242243
)
243244
self._original_frame_chain = self.driver.frame_chain.clone()
244245

245-
if not self.driver.is_mobile_device():
246+
if not self.driver.is_mobile_platform:
246247
# hide scrollbar for main window
247248
self._try_hide_scrollbars()
248249

@@ -293,7 +294,7 @@ def _check_result_flow(self, name, check_settings):
293294
result = self._check_frame_fluent(name, check_settings)
294295
else:
295296
logger.debug("default case")
296-
if not self.driver.is_mobile_device():
297+
if not self.driver.is_mobile_platform:
297298
# required to prevent cut line on the last stitched part of the
298299
# page on some browsers (like firefox).
299300
self.driver.switch_to.default_content()
@@ -498,7 +499,7 @@ def _set_viewport_size(self, size):
498499
# logger.info("Ignored (viewport size given explicitly)")
499500
# return None
500501

501-
if not self.driver.is_mobile_device():
502+
if not self.driver.is_mobile_platform:
502503
original_frame = self.driver.frame_chain.clone()
503504
self.driver.switch_to.default_content()
504505

@@ -524,7 +525,7 @@ def _environment(self):
524525
logger.info("No OS set, checking for mobile OS...")
525526
# Since in Python Appium driver is the same for Android and iOS,
526527
# we need to use the desired capabilities to figure this out.
527-
if eyes_selenium_utils.is_mobile_device(self._driver):
528+
if eyes_selenium_utils.is_mobile_platform(self._driver):
528529
platform_name = self._driver.platform_name
529530
logger.info(platform_name + " detected")
530531
platform_version = self._driver.platform_version
@@ -667,7 +668,7 @@ def _try_hide_caret(self):
667668

668669
def _get_screenshot(self):
669670
with self._driver.switch_to.frames_and_back(self._original_frame_chain):
670-
if self.position_provider and not self.driver.is_mobile_device():
671+
if self.position_provider and not self.driver.is_mobile_platform:
671672
self.position_provider.push_state()
672673

673674
self._try_hide_caret()
@@ -682,7 +683,7 @@ def _get_screenshot(self):
682683
self._last_screenshot = self._viewport_screenshot(scale_provider)
683684

684685
with self._driver.switch_to.frames_and_back(self._original_frame_chain):
685-
if self.position_provider and not self.driver.is_mobile_device():
686+
if self.position_provider and not self.driver.is_mobile_platform:
686687
self.position_provider.pop_state()
687688

688689
return self._last_screenshot
@@ -756,10 +757,18 @@ def _viewport_screenshot(self, scale_provider):
756757
sleep(self.configuration.wait_before_screenshots / 1000.0)
757758
image = self._image_provider.get_image()
758759
self._debug_screenshot_provider.save(image, "original")
760+
759761
scale_provider.update_scale_ratio(image.width)
760762
pixel_ratio = 1 / scale_provider.scale_ratio
761763
if pixel_ratio != 1.0:
764+
logger.info("Scalling")
762765
image = image_utils.scale_image(image, 1.0 / pixel_ratio)
766+
self._debug_screenshot_provider.save(image, "scaled")
767+
768+
if not isinstance(self.cut_provider, NullCutProvider):
769+
logger.info("Cutting")
770+
image = self.cut_provider.cut(image)
771+
self._debug_screenshot_provider.save(image, "cutted")
763772

764773
return EyesWebDriverScreenshot.create_viewport(self._driver, image)
765774

@@ -781,7 +790,7 @@ def _ensure_element_visible(self, element):
781790
if self._target_element is None:
782791
# No element? we must be checking the window.
783792
return None
784-
if self.driver.is_mobile_device():
793+
if self.driver.is_mobile_platform:
785794
logger.debug("NATIVE context identified, skipping 'ensure element visible'")
786795
return None
787796

eyes_selenium/applitools/selenium/visual_grid/render_task.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
if typing.TYPE_CHECKING:
2121
from typing import Callable, Dict, Any, Text, List
22-
from applitools.common.visual_grid import RenderStatusResults
22+
from applitools.common import RenderStatusResults, Region
2323
from applitools.selenium.visual_grid import RunningTest, EyesConnector
2424

2525

@@ -36,7 +36,7 @@ class RenderTask(VGTask):
3636
rendering_info = attr.ib()
3737
region_selectors = attr.ib(hash=False, factory=list)
3838
size_mode = attr.ib(default=None)
39-
region_to_check = attr.ib(hash=False, default=None)
39+
region_to_check = attr.ib(hash=False, default=None) # type: Region
4040
agent_id = attr.ib(default=None)
4141
func_to_run = attr.ib(default=None, hash=False, repr=False) # type: Callable
4242

0 commit comments

Comments
 (0)