def intersected_region(self, region, coordinates_type): # type: (Region, CoordinatesType) -> Region argument_guard.not_none(region) argument_guard.not_none(coordinates_type) if region.is_size_empty: return Region.from_(region) original_coordinates_type = region.coordinates_type intersected_region = self.convert_region_location( region, original_coordinates_type, self.SCREENSHOT_AS_IS ) # If the request was context based, we intersect with the frame window. if original_coordinates_type in [self.CONTEXT_AS_IS, self.CONTEXT_RELATIVE]: intersected_region = intersected_region.intersect(self.frame_window) # If the request is screenshot based, we intersect with the image elif original_coordinates_type == self.SCREENSHOT_AS_IS: intersected_region = intersected_region.intersect( Region(0, 0, self.image.width, self.image.height) ) else: raise ValueError( "Unknown coordinates type: '%s'" % original_coordinates_type ) # If the intersection is empty we don't want to convert the coordinates. if intersected_region.is_size_empty: return intersected_region # Converting the result to the required coordinates type intersected_region = self.convert_region_location( intersected_region, self.SCREENSHOT_AS_IS, coordinates_type ) return intersected_region
def _full_page_screenshot(self, scale_provider): # type: (ScaleProvider) -> EyesWebDriverScreenshot logger.info("Full page screenshot requested") original_fc = self.driver.frame_chain.clone() if original_fc.size > 0: original_frame_position = original_fc.default_content_scroll_position else: original_frame_position = Point.ZERO() with self.driver.switch_to.frames_and_back(self._original_fc): scroll_root_element = eyes_selenium_utils.curr_frame_scroll_root_element( self.driver) origin_provider = ScrollPositionProvider(self.driver, scroll_root_element) origin_provider.set_position(Point.ZERO()) logger.debug("resetting origin_provider location") location = self.scroll_root_element.location size_and_borders = self.scroll_root_element.size_and_borders region = Region( location["x"] + size_and_borders.borders["left"], location["y"] + size_and_borders.borders["top"], size_and_borders.size["width"], size_and_borders.size["height"], ) algo = self._create_full_page_capture_algorithm(scale_provider) image = algo.get_stitched_region(region, Region.EMPTY(), self.position_provider) return EyesWebDriverScreenshot.create_full_page( self._driver, image, original_frame_position)
def test_coded_layout_regions_passed_to_match_window_request( driver, fake_connector_class, vg_runner, spy): eyes = Eyes(vg_runner) eyes.server_connector = fake_connector_class() driver.get( "https://applitools.github.io/demo/TestPages/SimpleTestPage/index.html" ) eyes.open(driver, "Test Visual Grid", "Test regions are passed to render request") eyes.check(Target.window().fully().layout(Region(1, 2, 3, 4)).floating( 5, Region(6, 7, 8, 9)).accessibility(Region(10, 11, 12, 13), AccessibilityRegionType.LargeText)) eyes.close_async() server_connector = vg_runner._get_all_running_tests( )[0].eyes.server_connector vg_runner.get_all_test_results(False) _, match_data = server_connector.input_calls["match_window"][0] ims = match_data.options.image_match_settings assert len(server_connector.input_calls["match_window"]) == 1 assert ims.layout_regions == [Region(1, 2, 3, 4)] assert ims.floating_match_settings == [ FloatingMatchSettings(Region(6, 7, 8, 9), FloatingBounds(5, 5, 5, 5)) ] assert ims.accessibility == [ AccessibilityRegion(10, 11, 12, 13, AccessibilityRegionType.LargeText) ]
def __attrs_post_init__(self): # type: () -> None self._screenshot_type = update_screenshot_type( self._screenshot_type, self._image, self._driver ) position_provider = eyes_selenium_utils.get_cur_position_provider(self._driver) if not self._driver.is_mobile_app: self._frame_chain = self._driver.frame_chain.clone() frame_size = self.get_frame_size(position_provider) self._current_frame_scroll_position = eyes_selenium_utils.get_updated_scroll_position( # noqa position_provider ) self.updated_frame_location_in_screenshot( self._frame_location_in_screenshot ) logger.debug("Calculating frame window...") self.frame_window = Region.from_( self._frame_location_in_screenshot, frame_size ) else: self._frame_chain = FrameChain() self._current_frame_scroll_position = Point.ZERO() self._frame_location_in_screenshot = Point.ZERO() self.frame_window = Region.from_( self._frame_location_in_screenshot, self.image ) self.frame_window = self.frame_window.intersect(Region.from_(self.image))
def get_region(): rect = check_settings.values.target_region if rect is None: if self.driver.is_mobile_platform: bounds = self._target_element.rect else: bounds = self._target_element.bounding_client_rect region = Region( bounds["x"], bounds["y"], bounds["width"], bounds["height"], coordinates_type=CoordinatesType.CONTEXT_RELATIVE, ) else: s = self._target_element.size_and_borders.size b = self._target_element.size_and_borders.borders p = Point.from_(self._target_element.location) p = p.offset(b["left"], b["top"]) x = p.x + rect.left y = p.y + rect.top w = min(p.x + s["width"], rect.right) - x h = min(p.y + s["height"], rect.bottom) - y region = Region(x, y, w, h, CoordinatesType.CONTEXT_RELATIVE) return region
def __attrs_post_init__(self): # type: () -> None self._frame_chain = self._driver.frame_chain.clone() self._screenshot_type = update_screenshot_type( self._screenshot_type, self._image, self._driver ) cur_frame_position_provider = self._driver.eyes.current_frame_position_provider if cur_frame_position_provider: position_provider = cur_frame_position_provider else: position_provider = self._driver.eyes.position_provider if self._current_frame_scroll_position is None: self._current_frame_scroll_position = get_updated_scroll_position( position_provider ) self._frame_location_in_screenshot = self.get_updated_frame_location_in_screenshot( self._frame_location_in_screenshot ) logger.debug("Calculating frame window...") if self.frame_window is None: frame_size = self.get_frame_size(position_provider) self.frame_window = Region.from_location_size( self._frame_location_in_screenshot, frame_size ) self.frame_window.intersect( Region(0, 0, width=self.image.width, height=self.image.height) )
def test_floating_region_by_coordinates(check_settings_keyword): res = SeleniumCheckSettings().floating(34, Region(23, 44, 55, 66)) assert res == check_settings_keyword.floating_region_with_max_offset_by_coordinates( 34, "[23 44 55 66]") res = SeleniumCheckSettings().floating(Region(23, 44, 55, 66), 20, 30, 40, 50) assert res == check_settings_keyword.floating_region_by_coordinates( "[23 44 55 66]", 20, 30, 40, 50)
def from_screenshot(cls, driver, image, screenshot_region): # type: (EyesWebDriver, Image.Image, Region) -> EyesWebDriverScreenshot return cls( driver, image, ScreenshotType.ENTIRE_FRAME, Point.ZERO(), frame_window=Region.from_(Point.ZERO(), screenshot_region.size), region_window=Region.from_(screenshot_region), )
def _full_page_screenshot(self, scale_provider): # type: (ScaleProvider) -> EyesWebDriverScreenshot logger.info("Full page screenshot requested") original_fc = self.driver.frame_chain.clone() if original_fc.size > 0: original_frame_position = original_fc.default_content_scroll_position else: original_frame_position = Point.zero() with self.driver.switch_to.frames_and_back(self._original_frame_chain): location = self.scroll_root_element.location size_and_borders = self.scroll_root_element.size_and_borders region = Region( location["x"] + size_and_borders.borders["left"], location["y"] + size_and_borders.borders["top"], size_and_borders.size["width"], size_and_borders.size["height"], ) algo = self._create_full_page_capture_algorithm(scale_provider) image = algo.get_stitched_region(region, None, self.position_provider) return EyesWebDriverScreenshot.create_full_page( self._driver, image, original_frame_position)
def test_test_results_deserialization(): tr = json_utils.attr_from_json(get_resource("unit/testResultsData.json"), TestResults) # type: TestResults assert tr.status == TestResultsStatus.Passed assert ( tr.app_urls.batch == "https://eyes.applitools.com/app/test-results/111?accountIdPczBANNug~~" ) assert tr.accessibility_status == SessionAccessibilityStatus( AccessibilityStatus.Failed, AccessibilityLevel.AA, AccessibilityGuidelinesVersion.WCAG_2_0, ) assert tr.host_display_size == RectangleSize(800, 800) assert tr.default_match_settings.ignore_regions == [ Region(300, 300, 300, 300) ] assert tr.default_match_settings.accessibility == [ AccessibilityRegion(300, 300, 300, 300, AccessibilityRegionType.BoldText) ] assert tr.steps_info[0].name == "Login Window" assert ( tr.steps_info[0].app_urls.step == "https://eyes.applitools.com/app/test-results/00000215/steps/1?accountId=~" )
def compensate_region_position(self, region, pixel_ratio): logger.info(str(self._useragent)) logger.info(pixel_ratio) if ( self._useragent.os == OSNames.Windows and self._useragent.os_major_version <= 7 ): logger.info("compensating by {} pixels".format(pixel_ratio)) return region.offset(0, pixel_ratio) if pixel_ratio == 1.0: return region if self._useragent.browser_major_version > 60: return region driver = self._eyes.driver # type: EyesWebDriver fc = driver.frame_chain logger.info("frame_chain size: {}".format(fc.size)) if fc.size > 0: return region region = region.offset(0, -math.ceil(pixel_ratio / 2)) if region.width <= 0 or region.height <= 0: return Region.EMPTY() return region
def test_access_by_int_to_inherited_obj(): r = Region(0, 1, 2, 3) assert r.left == r[0] assert r.top == r[1] assert r.width == r[2] assert r.height == r[3] assert r.coordinates_type == r[4]
def test_access_by_keys_to_inherited_obj(): r = Region(0, 1, 2, 3) assert r.left == r["left"] assert r.top == r["top"] assert r.width == r["width"] assert r.height == r["height"] assert r.coordinates_type == r["coordinates_type"]
def demarshal_locate_result(results): # type: (dict) -> Dict[Text, List[APIRegion]] return { locator_id: [APIRegion.from_(region) for region in regions] if regions else [] for locator_id, regions in results.items() }
def _set_viewport_size(self, size): """ Use this method only if you made a previous call to `open`. """ # if self.viewport_size: # logger.info("Ignored (viewport size given explicitly)") # return None if not self.driver.is_mobile_platform: original_frame = self.driver.frame_chain.clone() self.driver.switch_to.default_content() try: self.set_viewport_size(self._driver, size) self._effective_viewport = Region( 0, 0, width=size["width"], height=size["height"], coordinates_type=CoordinatesType.SCREENSHOT_AS_IS, ) finally: # Just in case the user catches this error self.driver.switch_to.frames(original_frame) self.configure.viewport_size = RectangleSize(size["width"], size["height"])
def _ensure_frame_visible(self): logger.debug("scroll_root_element_: {}".format(self._scroll_root_element)) current_fc = self.driver.frame_chain.clone() fc = self.driver.frame_chain.clone() self.driver.execute_script("window.scrollTo(0,0);") origin_driver = eyes_selenium_utils.get_underlying_driver(self.driver) while len(fc) > 0: logger.debug("fc count: {}".format(fc.size)) self.driver.switch_to.parent_frame_static(origin_driver.switch_to, fc) self.driver.execute_script("window.scrollTo(0,0);") child_frame = fc.pop() parent_frame = fc.peek scroll_root_element = None if fc.size == self._original_fc.size: logger.debug("PositionProvider: {}".format(self.position_provider)) self._position_memento = self.position_provider.get_state() scroll_root_element = self._scroll_root_element else: if parent_frame: scroll_root_element = parent_frame.scroll_root_element if not scroll_root_element: scroll_root_element = self.driver.find_element_by_tag_name("html") logger.debug("scroll_root_element {}".format(scroll_root_element)) position_provider = self._element_position_provider_from( scroll_root_element ) position_provider.set_position(child_frame.location) reg = Region.from_(Point.ZERO(), child_frame.inner_size) self._effective_viewport.intersect(reg) self.driver.switch_to.frames(current_fc) return current_fc
def get_image(self): image = TakesScreenshotImageProvider(self._eyes).get_image() if self._eyes.is_cut_provider_explicitly_set: return image scale_ratio = self._eyes.device_pixel_ratio original_viewport_size = self._eyes._get_viewport_size() viewport_size = original_viewport_size.scale(scale_ratio) logger.info("logical viewport size: {}".format(original_viewport_size)) force_full_page_screenshot = self._eyes.configure.force_full_page_screenshot if force_full_page_screenshot is not None: if not force_full_page_screenshot: current_frame_chain = self._eyes.driver.frame_chain # type: FrameChain if len(current_frame_chain) == 0: position_provider = ScrollPositionProvider( self._eyes.driver, self._eyes.driver.find_element_by_tag_name("html"), ) loc = position_provider.get_current_position() else: loc = current_frame_chain.default_content_scroll_position loc = loc.scale(scale_ratio) image = image_utils.crop_image( image, Region.from_(loc, viewport_size)) return image
def _get_region_in_screenshot(self, region, image, pixel_ratio): # type: (Region, Image, float) -> Region if region.is_size_empty: return region logger.info("Creating screenshot object...") # We need the screenshot to be able to convert the region to screenshot coordinates. screenshot = self.screenshot_factory.make_screenshot( image ) # type: EyesWebDriverScreenshot logger.info("Getting region in screenshot...") region_in_screenshot = screenshot.intersected_region( region, CoordinatesType.SCREENSHOT_AS_IS ) logger.info("Region in screenshot: {}".format(region_in_screenshot)) region_in_screenshot = region_in_screenshot.scale(pixel_ratio) logger.info("Scaled region: {}".format(region_in_screenshot)) region_in_screenshot = self.region_position_compensation.compensate_region_position( region_in_screenshot, pixel_ratio ) # Handling a specific case where the region is actually larger than # the screenshot (e.g., when body width/height are set to 100%, and # an internal div is set to value which is larger than the viewport). region_in_screenshot.intersect(Region.from_(image)) logger.info("Region after intersect: {}".format(region_in_screenshot)) return region_in_screenshot
def _crop_if_smaller( self, full_area, last_successful_location, last_successful_part_size, stitched_image, ): # type: (Region, Point, RectangleSize, Image) -> Image act_image_width = last_successful_location.x + last_successful_part_size.width act_image_height = last_successful_location.y + last_successful_part_size.height logger.info("Extracted entire size: {}".format(full_area.size)) logger.info( "Actual stitched size: {} x {}".format(act_image_width, act_image_height) ) self.debug_screenshot_provider.save( stitched_image, self._debug_msg("_stitched_before_trim") ) if ( act_image_width < stitched_image.width or act_image_height < stitched_image.height ): logger.info("Trimming unnecessary margins...") stitched_image = image_utils.get_image_part( stitched_image, Region( 0, 0, min([act_image_width, stitched_image.width]), min([act_image_height, stitched_image.height]), ), ) logger.info("Done") return stitched_image
class TestData(object): method = attr.ib(type=str) check_tag = attr.ib(default=None) check_region = attr.ib(default=None) check_region_result = attr.ib(default=None) check_settings_data = CheckSettingsData( params=["Ignore Region By Coordinates", "[34 34 34 34]"], result=[RegionByRectangle(Region(34, 34, 34, 34))], ) __test__ = False # avoid warnings in test frameworks @property def check_params(self): # type: () -> List result = [] # order does matter here! if self.check_region: result.append(self.check_region) if self.check_tag: result.append(self.check_tag) if self.check_settings_data.params: result.extend(self.check_settings_data.params) return result def __str__(self): return "{} {}".format(self.method, "with tag" if self.check_tag else "without tag")
def to_region(self, size): # type: (Union[RectangleSize, Dict]) -> Region return Region( left=self.left, top=self.header, width=size["width"] - self.left - self.right, height=size["height"] - self.header - self.footer, )
def get_region(): location = self._target_element.location size = self._target_element.size return Region( location["x"], location["y"], size["width"], size["height"], coordinates_type=CoordinatesType.CONTEXT_RELATIVE, )
def from_screenshot(cls, driver, image, screenshot_region, frame_location_in_parent_screenshot): # type: (EyesWebDriver, Image.Image, Region, Point) -> EyesWebDriverScreenshot return cls( driver, image, ScreenshotType.ENTIRE_FRAME, frame_location_in_parent_screenshot - screenshot_region.location, frame_window=Region.from_(Point.ZERO(), screenshot_region.size), )
def create_entire_frame(cls, driver, image, entire_frame_size): # type: (EyesWebDriver, Image.Image, RectangleSize) -> EyesWebDriverScreenshot return cls( driver, image, ScreenshotType.ENTIRE_FRAME, frame_location_in_screenshot=Point(0, 0), current_frame_scroll_position=Point(0, 0), frame_window=Region.from_(Point(0, 0), entire_frame_size), )
def _check_element(self, name, check_settings): element = self._target_element # type: EyesWebElement self._region_to_check = None scroll_root_element = eyes_selenium_utils.current_frame_scroll_root_element( self.driver) pos_provider = self._create_position_provider(scroll_root_element) result = None with pos_provider: self._ensure_element_visible(element) pl = element.location try: self._check_frame_or_element = True display_style = element.get_computed_style("display") if self.configuration.hide_scrollbars: # FIXME bug if trying to hide element.hide_scrollbars() size_and_borders = element.size_and_borders border_widths = size_and_borders.borders element_size = size_and_borders.size if display_style != "inline" and ( element_size["height"] <= self._effective_viewport["height"] and element_size["width"] <= self._effective_viewport["width"]): self._element_position_provider = ElementPositionProvider( self.driver, element) else: self._element_position_provider = None element_region = Region( pl["x"] + border_widths["left"], pl["y"] + border_widths["top"], element_size["width"], element_size["height"], coordinates_type=CoordinatesType.SCREENSHOT_AS_IS, ) self._region_to_check = element_region if not self._effective_viewport.is_size_empty: self._region_to_check.intersect(self._effective_viewport) result = self._check_window_base(NULL_REGION_PROVIDER, name, False, check_settings) except Exception as e: logger.exception(e) raise e finally: if self.configuration.hide_scrollbars: element.return_to_original_overflow() self._check_frame_or_element = False self._region_to_check = None self._element_position_provider = None return result
def test_perform_match_collect_regions_from_screenshot( mwt, app_output_with_screenshot, eyes_base_mock): ignore_region = Region(5, 6, 7, 8) max_offset = 25 floating_region = Region(0, 1, 2, 3) content_region = Region(1, 2, 2, 1) accessibility_region = AccessibilityRegion( 1, 2, 1, 2, AccessibilityRegionType.GraphicalObject) check_settings = (CheckSettings().ignore(ignore_region).floating( max_offset, floating_region).content(content_region).accessibility( accessibility_region)) image_match_settings = mwt.create_image_match_settings( check_settings, eyes_base_mock) with patch("applitools.core.server_connector.ServerConnector.match_window" ) as smw: mwt.perform_match( app_output_with_screenshot, "Name", False, image_match_settings, eyes_base_mock, check_settings=check_settings, ) match_window_data = smw.call_args[0][1] # type: MatchWindowData ims = match_window_data.options.image_match_settings assert ims.content_regions == [content_region] assert ims.ignore_regions == [ignore_region] assert ims.floating_match_settings == [ FloatingMatchSettings( region=floating_region, bounds=FloatingBounds( max_up_offset=max_offset, max_down_offset=max_offset, max_left_offset=max_offset, max_right_offset=max_offset, ), ) ] assert ims.accessibility == [accessibility_region]
def _region_from_element(element, screenshot): location = element.location size = element.size if screenshot: # Element's coordinates are context relative, so we need to convert them first. adjusted_location = screenshot.location_in_screenshot( Point(location["x"], location["y"]), CoordinatesType.CONTEXT_RELATIVE) else: adjusted_location = Point(location["x"], location["y"]) region = Region.from_location_size(adjusted_location, size) return region
def full_frame_or_element_region(check_settings): logger.debug("check_frame_or_element: {}".format( self._check_frame_or_element)) if self._check_frame_or_element: fc = self._ensure_frame_visible() # FIXME - Scaling should be handled in a single place instead scale_factory = self._update_scaling_params() screenshot_image = self._image_provider.get_image() scale_factory.update_scale_ratio(screenshot_image.width) self.driver.switch_to.frames(fc) screenshot = EyesWebDriverScreenshot.create_viewport( self.driver, screenshot_image) # TODO HERE logger.debug("replacing region_to_check") self._region_to_check = screenshot.frame_window self._full_region_to_check = Region.EMPTY() target_region = check_settings.values.target_region if target_region is None: target_region = Region.EMPTY() return target_region
def _get_viewport_scroll_bounds(self): switch_to = self.driver.switch_to with switch_to.frames_and_back(self._original_fc): try: location = eyes_selenium_utils.get_current_position( self.driver, self.scroll_root_element) except WebDriverException as e: logger.warning(str(e)) logger.info("Assuming position is 0,0") location = Point(0, 0) viewport_bounds = Region.from_(location, self._get_viewport_size()) return viewport_bounds
def cut(self, image): # type: (Image) -> Image if self.header == 0 and self.footer == 0 and self.right == 0 and self.left == 0: return image target_region = Region( self.left, self.header, image.width - self.left - self.right, image.height - self.header - self.footer, ) return image_utils.crop_image(image, target_region)