Esempio n. 1
0
    def sub_screenshot(self, region, throw_if_clipped=False):
        # type: (Region, bool) -> EyesImagesScreenshot
        argument_guard.not_none(region)

        # We want to get the sub-screenshot in as-is coordinates type.
        sub_screenshot_region = self.intersected_region(
            region, self.SCREENSHOT_AS_IS)

        if sub_screenshot_region.is_size_empty and (
                throw_if_clipped
                or not sub_screenshot_region.size == region.size):
            raise OutOfBoundsError(
                "Region [{}] is out of screenshot bounds [{}]".format(
                    region, self._bounds))

        sub_screenshot_image = image_utils.get_image_part(
            self._image, sub_screenshot_region)

        # Notice that we need the bounds-relative coordinates as parameter
        # for new sub-screenshot.
        relative_sub_screenshot_region = self.convert_region_location(
            sub_screenshot_region, self.SCREENSHOT_AS_IS,
            self.CONTEXT_RELATIVE)
        return EyesImagesScreenshot(sub_screenshot_image,
                                    relative_sub_screenshot_region.location)
Esempio n. 2
0
 def add_device_emulation(self,
                          device_name,
                          orientation=ScreenOrientation.PORTRAIT):
     # type: (DeviceName, ScreenOrientation) -> Configuration
     argument_guard.not_none(device_name)
     self.add_browser(ChromeEmulationInfo(device_name, orientation))
     return self
    def render_status_by_id(self, *render_ids):
        # type: (*Text) -> List[RenderStatusResults]
        argument_guard.not_none(render_ids)
        if self._render_info is None:
            raise EyesError("render_info must be fetched first")

        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = "application/json"
        headers["X-Auth-Token"] = self._render_info.access_token
        url = urljoin(self._render_info.service_url, self.RENDER_STATUS)
        response = self._com.request(
            requests.post,
            url,
            use_api_key=False,
            headers=headers,
            data=json.dumps(render_ids),
        )
        if not response.ok:
            raise EyesError(
                "Error getting server status, {} {}".format(
                    response.status_code, response.content
                )
            )
        # TODO: improve parser to handle similar names
        return json_utils.attr_from_response(response, RenderStatusResults)
Esempio n. 4
0
    def normalize_rotation(driver, image, rotation):
        # type: (WebDriver, Image, Optional[int]) -> Image
        """
        Rotates the image as necessary. The rotation is either manually forced
        by passing a non-null rotation, or automatically inferred.

        :param driver: The underlying driver which produced the screenshot.
        :param image: The image to normalize.
        :param rotation: The degrees by which to rotate the image:
                         positive values = clockwise rotation,
                         negative values = counter-clockwise,
                         0 = force no rotation,
                         null = rotate automatically as needed.
        :return: A normalized image.
        """
        argument_guard.not_none(driver)
        argument_guard.not_none(image)
        normalized_image = image
        if rotation and rotation != 0:
            normalized_image = image_utils.rotate_image(image, rotation)
        else:  # Do automatic rotation if necessary
            try:
                logger.info("Trying to automatically normalize rotation...")
                if (eyes_selenium_utils.is_mobile_app(driver) and
                        eyes_selenium_utils.is_landscape_orientation(driver)
                        and image.height > image.width):
                    # For Android, we need to rotate images to the right,
                    # and for iOS to the left.
                    degree = 90 if eyes_selenium_utils.is_android(
                        driver) else -90
                    normalized_image = image_utils.rotate_image(image, degree)
            except Exception as e:
                logger.exception(e)
                logger.info("Skipped automatic rotation handling.")
        return normalized_image
Esempio n. 5
0
    def get_locators(self, visual_locator_settings):
        # type: (VisualLocatorSettings) -> LOCATORS_TYPE
        argument_guard.not_none(visual_locator_settings)

        logger.info(
            "Get locators with given names: {}".format(visual_locator_settings.names)
        )
        logger.info("Requested viewport screenshot for visual locators..")
        viewport_screenshot = self._get_viewport_screenshot()
        self._debug_screenshot_provider.save(
            viewport_screenshot,
            "Visual locators: {}".format(visual_locator_settings.names),
        )
        image = image_utils.get_bytes(viewport_screenshot)
        logger.info("Post visual locators screenshot...")
        viewport_screenshot_url = self._server_connector.try_upload_image(image)

        logger.info("Screenshot URL: {}".format(viewport_screenshot_url))
        data = VisualLocatorsData(
            app_name=self._eyes.configure.app_name,
            image_url=viewport_screenshot_url,
            first_only=visual_locator_settings.values.is_first_only,
            locator_names=visual_locator_settings.values.names,
        )
        logger.info("Post visual locators: {}".format(data))
        return self._server_connector.post_locators(data)
    def get_text_regions(self, config):
        # type: (TextRegionSettings) -> PATTERN_TEXT_REGIONS
        def get_app_output():
            scale_provider = self._eyes.update_scaling_params()
            viewport_screenshot = self._eyes.get_scaled_cropped_viewport_image(
                scale_provider)
            image = image_utils.get_bytes(viewport_screenshot)
            screenshot_url = self._server_connector.try_upload_image(image)

            dom_json = self._eyes._try_capture_dom()
            dom_url = self._eyes._try_post_dom_capture(dom_json)
            return AppOutput(dom_url=dom_url,
                             screenshot_url=screenshot_url,
                             location=Point.ZERO())

        argument_guard.not_none(config._patterns)
        data = TextSettingsData(
            app_output=get_app_output(),
            patterns=config._patterns,
            ignore_case=config._ignore_case,
            first_only=config._first_only,
            language=config._language,
        )
        return self._server_connector.get_text_regions_in_running_session_image(
            data)
Esempio n. 7
0
    def render_put_resource(self, resource):
        # type: (VGResource) -> Text
        argument_guard.not_none(resource)
        if self._render_info is None:
            raise EyesError("render_info must be fetched first")

        logger.debug("resource hash: {} url: {}".format(resource.hash, resource.url))
        content = resource.content
        argument_guard.not_none(content)
        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = resource.content_type
        headers["X-Auth-Token"] = self._render_info.access_token

        url = urljoin(
            self._render_info.service_url, self.RESOURCES_SHA_256 + resource.hash
        )
        response = self._com.request(
            "put",
            url,
            use_api_key=False,
            headers=headers,
            data=content,
            params={"render-id": "NONE"},
        )
        logger.debug("ServerConnector.put_resource - request succeeded")
        if not response.ok:
            raise EyesError(
                "Error putting resource: {}, {}".format(
                    response.status_code, response.content
                )
            )
        return resource.hash
Esempio n. 8
0
    def _do_switch_to_frame(self, target_frame):
        # type: (EyesWebElement) -> None
        """
        Will be called when switching into a frame.

        :param target_frame: The element to be switched to.
        """
        argument_guard.not_none(target_frame)

        size_and_borders = target_frame.size_and_borders
        borders = size_and_borders.borders
        frame_inner_size = size_and_borders.size
        bounds = target_frame.bounding_client_rect

        content_location = Point(
            bounds["x"] + borders["left"], bounds["y"] + borders["top"]
        )
        outer_size = RectangleSize.from_(target_frame.size)
        inner_size = RectangleSize.from_(frame_inner_size)
        original_location = target_frame.scroll_location

        self._switch_to.frame(target_frame.element)

        scroll_root_element = self._driver.find_element_by_xpath("/*")
        frame = Frame(
            reference=target_frame,
            location=content_location,
            outer_size=outer_size,
            inner_size=inner_size,
            parent_scroll_position=original_location,
            scroll_root_element=scroll_root_element,
        )
        self._driver.frame_chain.push(frame)
Esempio n. 9
0
    def open(self, driver):
        # type: (EyesWebDriver) -> EyesWebDriver
        self._test_uuid = uuid.uuid4()
        if self.configuration.is_disabled:
            return driver
        logger.open_()
        argument_guard.not_none(driver)
        logger.debug("VisualGridEyes.open(%s)" % self.configuration)

        self._driver = driver
        browsers_info = self.configuration.browsers_info

        if self.configuration.viewport_size:
            self._set_viewport_size(self.configuration.viewport_size)
        elif browsers_info:
            viewports = [bi.viewport_size for bi in browsers_info]
            if viewports:
                self.configuration.viewport_size = viewports[0]
        else:
            self.configuration.viewport_size = self._get_viewport_size()

        for b_info in browsers_info:
            test = RunningTest(self._create_vgeyes_connector(b_info),
                               self.configuration, b_info)
            test.on_results_received(
                lambda r: self.vg_manager.aggregate_result(test, r))
            test.test_uuid = self._test_uuid
            self.test_list.append(test)
        self._is_opened = True
        self.vg_manager.open(self)
        logger.info("VisualGridEyes opening {} tests...".format(
            len(self.test_list)))
        return driver
    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 open(self, driver):
        # type: (EyesWebDriver) -> EyesWebDriver
        self._test_uuid = uuid.uuid4()
        argument_guard.not_none(driver)
        logger.debug("VisualGridEyes.open(%s)" % self.configure)

        self._driver = driver
        self._set_viewport_size()
        self.server_connector.update_config(
            self.configure,
            self.full_agent_id,
            ua_string=self.driver.user_agent.origin_ua_string,
        )
        self.server_connector.render_info()
        self.vg_manager.rendering_service.maybe_set_server_connector(
            self.server_connector)

        for browser_info, job_info in self._job_info_for_browser_info(
                self.configure.browsers_info):
            test = RunningTest(
                self._create_vgeyes_connector(browser_info, job_info),
                self.configure.clone(),
                browser_info,
                self.vg_manager.rendering_service,
            )
            test.on_results_received(self.vg_manager.aggregate_result)
            test.test_uuid = self._test_uuid
            self.test_list.append(test)
            test.becomes_not_opened()
        self._is_opened = True
        self.vg_manager.open(self)
        logger.info("VisualGridEyes opening {} tests...".format(
            len(self.test_list)))
        return driver
Esempio n. 12
0
 def add_device_emulation(self,
                          device_name,
                          orientation=ScreenOrientation.PORTRAIT):
     argument_guard.not_none(device_name)
     emu = ChromeEmulationInfo(device_name, orientation)
     self.add_browser(RenderBrowserInfo(emulation_info=emu))
     return self
 def __init__(self, runner, config):
     # type: (VisualGridRunner, Eyes)-> None
     self._config_provider = config
     self._elements = []
     argument_guard.not_none(runner)
     self.vg_manager = runner
     self.test_list = []  # type: List[RunningTest]
Esempio n. 14
0
    def will_switch_to_frame(self, target_frame):
        # type: (EyesWebElement) -> None
        """
        Will be called before switching into a frame.

        :param target_frame: The element about to be switched to.
        """
        argument_guard.not_none(target_frame)
        pl = target_frame.location

        size_and_borders = target_frame.size_and_borders
        borders = size_and_borders.borders
        frame_inner_size = size_and_borders.size

        content_location = Point(pl["x"] + borders["left"],
                                 pl["y"] + borders["top"])
        sp = ScrollPositionProvider(
            self._driver, self._driver.find_element_by_tag_name("html"))
        original_location = sp.get_current_position()
        sp.set_position(original_location)
        frame = Frame(
            target_frame,
            content_location,
            target_frame.size,
            frame_inner_size,
            parent_scroll_position=original_location,
        )
        self._driver.frame_chain.push(frame)
 def __init__(self, config_provider, runner):
     # type: (Eyes, VisualGridRunner)-> None
     self._config_provider = config_provider
     self._elements = []
     argument_guard.not_none(runner)
     self.vg_manager = runner  # type: VisualGridRunner
     self.test_list = []  # type: List[RunningTest]
     self._test_uuid = None
     self.server_connector = None  # type: Optional[ServerConnector]
 def __init__(self, config_provider, runner):
     # type: (Eyes, VisualGridRunner)-> None
     self._config_provider = config_provider
     self._elements = []
     argument_guard.not_none(runner)
     self.vg_manager = runner  # type: VisualGridRunner
     self.test_list = []  # type: List[RunningTest]
     self._test_uuid = None
     self.server_connector = ServerConnector()  # type: ServerConnector
     self.resource_collection_queue = [
     ]  # type: List[ResourceCollectionTask]
Esempio n. 17
0
    def open(
        self,
        driver,  # type: AnyWebDriver
        app_name=None,  # type: Optional[Text]
        test_name=None,  # type: Optional[Text]
        viewport_size=None,  # type: Optional[ViewPort]
    ):
        # type: (...) -> Optional[EyesWebDriver]
        """
        Starts a test.

        :param driver: The driver that controls the browser hosting the application
            under the test.
        :param app_name: The name of the application under test.
        :param test_name: The test name.
        :param viewport_size: The client's viewport size (i.e.,
            the visible part of the document's body) or None to allow any viewport size.
        :raise EyesError: If the session was already open.
        """
        if self.configure.is_disabled:
            logger.info("open(): ignored (disabled)")
            return

        if app_name:
            self.configure.app_name = app_name
        if test_name:
            self.configure.test_name = test_name
        if viewport_size:
            self.configure.viewport_size = viewport_size  # type: ignore

        argument_guard.not_none(
            self.configure.app_name, ValueError("app_name is required")
        )
        argument_guard.not_none(
            self.configure.test_name, ValueError("test_name is required")
        )

        logger.info(
            "open(app_name={}, test_name={}, viewport_size={})".format(
                self.configure.app_name,
                self.configure.test_name,
                self.configure.viewport_size,
            )
        )

        self._init_driver(driver)
        self._init_additional_providers()
        if self._is_visual_grid_eyes:
            self._selenium_eyes.open(self._driver, skip_start_session=True)

        result = self._current_eyes.open(self.driver)
        self._is_opened = True
        return result
Esempio n. 18
0
 def delete_session(self, test_results):
     # type: (TestResults) -> None
     argument_guard.not_none(test_results)
     if None in (test_results.id, test_results.batch_id, test_results.secret_token):
         logger.error("Can't delete session, results are None")
         return
     self._com.request(
         "delete",
         "{}/{}/{}".format(
             self.API_SESSIONS_BATCHES, test_results.batch_id, test_results.id
         ),
         params={"AccessToken": test_results.secret_token},
     ).raise_for_status()
Esempio n. 19
0
    def location_in_screenshot(self, location, coordinates_type):
        # type: (Point, CoordinatesType) -> Point
        argument_guard.not_none(location)
        argument_guard.not_none(coordinates_type)
        location = self.convert_location(location, coordinates_type,
                                         self.CONTEXT_RELATIVE)

        if not self._bounds.contains(location):
            raise OutOfBoundsError(
                "Point {} ('{}') is not visible in screenshot!".format(
                    location, coordinates_type))

        return self.convert_location(location, self.CONTEXT_RELATIVE,
                                     self.SCREENSHOT_AS_IS)
Esempio n. 20
0
    def open_base(
        self,
        app_name,  # type: Text
        test_name,  # type: Text
        viewport_size=None,  # type: Optional[ViewPort]
        session_type=SessionType.SEQUENTIAL,  # type: SessionType
    ):
        # type: (...) -> None
        """
        Starts a test.

        :param app_name: The name of the application under test.
        :param test_name: The test name.
        :param viewport_size: The client's viewport size (i.e.,
                              the visible part of the document's body) or None to
                              allow any viewport size.
        :param session_type: The type of test (e.g., Progression for timing tests)
                              or Sequential by default.
        :return: An updated web driver
        :raise EyesError: If the session was already open.
        """
        logger.open_()
        if self.configuration.is_disabled:
            logger.debug("open_base(): ignored (disabled)")
            return

        if self._server_connector is None:
            raise EyesError("Server connector not set.")

        # If there's no default application name, one must be provided for the current test.
        if self.configuration.app_name is None:
            argument_guard.not_none(app_name)
            self.configuration.app_name = app_name

        argument_guard.not_none(test_name)
        self.configuration.test_name = test_name

        logger.info("\nAgent: {}\n".format(self.full_agent_id))
        logger.info(
            "open_base(%s, %s, %s, %s)"
            % (app_name, test_name, viewport_size, self.configuration.failure_reports)
        )
        self.configuration.session_type = session_type
        self.configuration.viewport_size = viewport_size

        self._open_base()
Esempio n. 21
0
    def _try_upload_data(self, bytes_data, content_type, media_type):
        # type: (bytes, Text, Text) -> Optional[Text]
        argument_guard.not_none(bytes_data)

        rendering_info = self.render_info()
        if rendering_info and rendering_info.results_url:
            try:
                target_url = rendering_info.results_url
                guid = uuid.uuid4()
                target_url = target_url.replace("__random__", str(guid))
                logger.debug("Uploading {} to {}".format(media_type, target_url))
                if self._upload_data(
                    bytes_data, rendering_info, target_url, content_type, media_type
                ):
                    return target_url
            except Exception as e:
                logger.error("Error uploading {}".format(media_type))
                logger.exception(e)
Esempio n. 22
0
    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)

        intersected_region = self.convert_region_location(
            region, region.coordinates_type, self.CONTEXT_RELATIVE)
        intersected_region.intersect(self._bounds)

        if region.is_size_empty:
            return region

        intersected_region.location = self.convert_location(
            intersected_region.location, self.CONTEXT_RELATIVE,
            coordinates_type)
        return intersected_region
Esempio n. 23
0
    def open(self, driver):
        # type: (EyesWebDriver) -> EyesWebDriver
        self._test_uuid = uuid.uuid4()
        logger.open_()
        argument_guard.not_none(driver)
        logger.debug("VisualGridEyes.open(%s)" % self.configure)

        self._driver = driver
        self._set_viewport_size()

        for b_info in self.configure.browsers_info:
            test = RunningTest(self._create_vgeyes_connector(b_info),
                               self.configure, b_info)
            test.on_results_received(self.vg_manager.aggregate_result)
            test.test_uuid = self._test_uuid
            self.test_list.append(test)
        self._is_opened = True
        self.vg_manager.open(self)
        logger.info("VisualGridEyes opening {} tests...".format(
            len(self.test_list)))
        return driver
Esempio n. 24
0
    def convert_location(self, location, from_, to):
        # type: (Point, CoordinatesType, CoordinatesType) -> Point
        argument_guard.not_none(location)
        argument_guard.not_none(from_)
        argument_guard.not_none(to)

        argument_guard.is_a(location, Point)

        result = location.clone()
        if from_ == to:
            return result

        if from_ == self.SCREENSHOT_AS_IS:
            if to == self.CONTEXT_RELATIVE:
                result = result.offset(self._bounds.left, self._bounds.top)
            else:
                raise CoordinatesTypeConversionError(from_, to)

        elif from_ == self.SCREENSHOT_AS_IS:
            if to == self.CONTEXT_RELATIVE:
                result = result.offset(-self._bounds.left, -self._bounds.top)
            else:
                raise CoordinatesTypeConversionError(from_, to)
        else:
            raise CoordinatesTypeConversionError(from_, to)

        return result
    def convert_location(self, location, from_, to):  # noqa: C901
        # type: (Point, CoordinatesType, CoordinatesType) -> Point
        argument_guard.not_none(location)
        argument_guard.not_none(from_)
        argument_guard.not_none(to)

        result = Point.from_(location)
        if from_ == to:
            return result

        # If we're not inside a frame, and the screenshot is the entire
        # page, then the context as-is/relative are the same (notice
        # screenshot as-is might be different, e.g.,
        # if it is actually a sub-screenshot of a region).
        if (len(self.frame_chain) == 0
                and self._screenshot_type == ScreenshotType.ENTIRE_FRAME):
            if (from_ == self.CONTEXT_RELATIVE or from_
                    == self.CONTEXT_AS_IS) and to == self.SCREENSHOT_AS_IS:
                # If this is not a sub-screenshot, this will have no effect.
                result = result.offset(self._frame_location_in_screenshot)
                # If this is not a region subscreenshot, this will have no effect.
                result = result.offset(-self.region_window.left,
                                       -self.region_window.top)
            elif from_ == self.SCREENSHOT_AS_IS and (
                    to == self.CONTEXT_RELATIVE or to == self.CONTEXT_AS_IS):
                result = result.offset(-self._frame_location_in_screenshot)
            return result

        if from_ == self.CONTEXT_AS_IS:
            if to == self.CONTEXT_RELATIVE:
                result = result.offset(self._current_frame_scroll_position)
            elif to == self.SCREENSHOT_AS_IS:
                result = result.offset(self._frame_location_in_screenshot)
            else:
                raise CoordinatesTypeConversionError(from_, to)
        elif from_ == self.CONTEXT_RELATIVE:
            if to == self.SCREENSHOT_AS_IS:
                # First, convert context-relative to context-as-is.
                result = result.offset(-self._current_frame_scroll_position)
                # Now convert context-as-is to screenshot-as-is
                result = result.offset(self._frame_location_in_screenshot)
            elif to == self.CONTEXT_AS_IS:
                result = result.offset(-self._current_frame_scroll_position)
            else:
                raise CoordinatesTypeConversionError(from_, to)
        elif from_ == self.SCREENSHOT_AS_IS:
            if to == self.CONTEXT_RELATIVE:
                # First, convert context-relative to context-as-is.
                result = result.offset(-self._frame_location_in_screenshot)
                # Now convert context-as-is to screenshot-as-is
                result = result.offset(self._current_frame_scroll_position)
            elif to == self.CONTEXT_AS_IS:
                result = result.offset(-self._frame_location_in_screenshot)
            else:
                raise CoordinatesTypeConversionError(from_, to)
        else:
            raise CoordinatesTypeConversionError(from_, to)
        return result
Esempio n. 26
0
 def get_viewport_size(driver):
     # type: (AnyWebDriver) -> ViewPort
     argument_guard.not_none(driver)
     return eyes_selenium_utils.get_viewport_size_or_display_size(driver)
Esempio n. 27
0
    def get_stitched_region(self, region, full_area, position_provider):
        # type: (Region, Optional[Region], Optional[PositionProvider]) -> Image.Image
        argument_guard.not_none(region)
        argument_guard.not_none(position_provider)

        logger.info(
            "region: %s ; full_area: %s ; position_provider: %s"
            % (region, full_area, position_provider.__class__.__name__)
        )

        origin_state = self.origin_provider.get_state()

        if self.origin_provider != position_provider:
            self.origin_provider.set_position(
                Point.ZERO()
            )  # first scroll to 0,0 so CSS stitching works.

        # Saving the original position (in case we were already in the outermost frame).
        original_stitched_state = position_provider.get_state()

        datetime_utils.sleep(self.wait_before_screenshots)
        initial_screenshot = self.image_provider.get_image()
        initial_size = RectangleSize.from_(initial_screenshot)

        pixel_ratio = self._get_pixel_ratio(initial_screenshot)
        scaled_cut_provider = self.cut_provider.scale(pixel_ratio)
        cutted_initial_screenshot = self._cut_if_needed(
            initial_screenshot, scaled_cut_provider
        )
        self.debug_screenshot_provider.save(
            cutted_initial_screenshot, self._debug_msg("cutted_initial_screenshot")
        )

        region_in_initial_screenshot = self._get_region_in_screenshot(
            region, cutted_initial_screenshot, pixel_ratio
        )
        cropped_initial_screenshot = self._crop_if_needed(
            cutted_initial_screenshot, region_in_initial_screenshot
        )
        self.debug_screenshot_provider.save(
            cropped_initial_screenshot, self._debug_msg("cropped_initial_screenshot")
        )

        scaled_initial_screenshot = image_utils.scale_image(
            cropped_initial_screenshot, self.scale_provider
        )
        self.debug_screenshot_provider.save(
            scaled_initial_screenshot, self._debug_msg("scaled_initial_screenshot")
        )
        if full_area is None or full_area.is_empty:
            entire_size = self._get_entire_size(initial_screenshot, position_provider)
            # Notice that this might still happen even if we used
            # "get_image_part", since "entire_page_size" might be that of a
            # frame
            if (
                scaled_initial_screenshot.width >= entire_size.width
                and scaled_initial_screenshot.height >= entire_size.height
            ):
                self.origin_provider.restore_state(origin_state)
                return scaled_initial_screenshot

            full_area = Region.from_(Point.ZERO(), entire_size)

        scaled_cropped_location = full_area.location
        physical_crop_location = Point.from_(scaled_cropped_location).scale(pixel_ratio)

        if region_in_initial_screenshot.is_empty:
            physical_crop_size = RectangleSize(
                initial_size.width - physical_crop_location.x,
                initial_size.height - physical_crop_location.y,
            )
            source_region = Region.from_(physical_crop_location, physical_crop_size)
        else:
            # Starting with the screenshot we already captured at (0,0).
            source_region = region_in_initial_screenshot

        scaled_cropped_source_rect = self.cut_provider.to_region(source_region.size)
        scaled_cropped_source_rect = scaled_cropped_source_rect.offset(
            source_region.left, source_region.top
        )
        scaled_cropped_source_region = dict(
            x=int(math.ceil(scaled_cropped_source_rect.left / pixel_ratio)),
            y=int(math.ceil(scaled_cropped_source_rect.top / pixel_ratio)),
            width=int(math.ceil(scaled_cropped_source_rect.width / pixel_ratio)),
            height=int(math.ceil(scaled_cropped_source_rect.height / pixel_ratio)),
        )
        scaled_cropped_size = dict(
            width=scaled_cropped_source_region["width"],
            height=scaled_cropped_source_region["height"],
        )

        # Getting the list of viewport regions composing the page
        # (we'll take screenshot for each one).
        if region_in_initial_screenshot.is_empty:
            x = max(0, full_area.left)
            y = max(0, full_area.top)
            w = min(full_area.width, scaled_cropped_size["width"])
            h = min(full_area.height, scaled_cropped_size["height"])
            rect_in_initial_screenshot = Region(
                round(x * pixel_ratio),
                round(y * pixel_ratio),
                round(w * pixel_ratio),
                round(h * pixel_ratio),
            )
        else:
            rect_in_initial_screenshot = region_in_initial_screenshot

        screenshot_parts = self._get_image_parts(
            full_area, scaled_cropped_size, pixel_ratio, rect_in_initial_screenshot
        )

        # Starting with element region size part of the screenshot. Use it as a size
        # template.
        stitched_image = Image.new("RGBA", (full_area.width, full_area.height))
        # Take screenshot and stitch for each screenshot part.
        stitched_image = self._stitch_screenshot(
            original_stitched_state,
            position_provider,
            screenshot_parts,
            stitched_image,
            self.scale_provider.scale_ratio,
            scaled_cut_provider,
        )
        position_provider.restore_state(original_stitched_state)
        self.origin_provider.restore_state(origin_state)
        return stitched_image
Esempio n. 28
0
 def _get_viewport_size(self):
     argument_guard.not_none(self.driver)
     return eyes_selenium_utils.get_viewport_size(self.driver)
Esempio n. 29
0
 def set_viewport_size(driver, size):
     # type: (AnyWebDriver, ViewPort) -> None
     argument_guard.not_none(driver)
     argument_guard.not_none(size)
     eyes_selenium_utils.set_viewport_size(driver, size)
Esempio n. 30
0
 def with_batch_id(self, id):
     # type: (Text) -> BatchInfo
     argument_guard.not_none(id)
     self.id = str(id)
     return self