Exemplo n.º 1
0
 def poll_render_status(self, render_request):
     # type: (RenderRequest) -> List[RenderStatusResults]
     iterations = 0
     statuses = []  # type: List[RenderStatusResults]
     if not render_request.render_id:
         raise EyesError("RenderStatus: Got empty renderId!")
     fails_count = 0
     finished = False
     while True:
         if finished:
             break
         while True:
             try:
                 statuses = self.eyes_connector.render_status_by_id(
                     render_request.render_id)
             except Exception as e:
                 logger.exception(e)
                 datetime_utils.sleep(1000)
                 fails_count += 1
             finally:
                 iterations += 1
                 datetime_utils.sleep(500)
             if statuses or 0 < fails_count < 3:
                 break
         finished = bool(statuses and statuses[0] is not None
                         and (statuses[0].status != RenderStatus.RENDERING
                              or iterations > self.MAX_ITERATIONS or False))
     if statuses[0].status == RenderStatus.ERROR:
         raise EyesError("Got error during rendering: \n\t{}".format(
             statuses[0].error))
     return statuses
Exemplo n.º 2
0
 def add_running_test(self, running_test):
     # type: (RunningTest) -> int
     if running_test in self.running_tests:
         raise EyesError("The running test {} already exists in the render "
                         "task".format(running_test))
     self.running_tests.append(running_test)
     return len(self.running_tests) - 1
Exemplo n.º 3
0
    def _check_image(self, region_provider, name, ignore_mismatch,
                     check_settings):
        # type: (RegionProvider, Text, bool, ImagesCheckSettings) -> bool
        # Set the title to be linked to the screenshot.
        self._raw_title = name if name else ""

        if not self._is_opened:
            self.abort()
            raise EyesError("you must call open() before checking")

        image = check_settings.values.image  # type: Image.Image

        if not isinstance(self.cut_provider, NullCutProvider):
            logger.debug("cutting...")
            image = self.cut_provider.cut(image)
            self.debug_screenshot_provider.save(image, "cut")

        self._screenshot = EyesImagesScreenshot(image)
        if not self.configure.viewport_size:
            self._set_viewport_size(
                RectangleSize(width=image.width, height=image.height))

        check_settings = check_settings.timeout(0)
        match_result = self._check_window_base(region_provider,
                                               self._raw_title,
                                               ignore_mismatch, check_settings)
        self._screenshot = None
        self._raw_title = None
        return match_result.as_expected
Exemplo n.º 4
0
    def _run_render_status_requests(self):
        status_tasks = []
        while True:
            with self._have_status_tasks:
                while not (self._shutdown or status_tasks
                           or self._status_tasks):
                    self._have_status_tasks.wait()
                if self._shutdown:
                    break
                new_tasks, self._status_tasks = self._status_tasks, []
            status_tasks.extend(new_tasks)
            ids = [t.render_id for t in status_tasks]
            logger.debug("render_status_by_id call with ids: {}".format(ids))
            try:

                statuses = self._server_connector.render_status_by_id(*ids)
            except Exception as e:
                for task in status_tasks:
                    task.on_error(e)
                continue
            rendering = []
            current_time = time()
            for status, task in zip(statuses, status_tasks):
                if status.status == RenderStatus.RENDERING:
                    if current_time > task.timeout_time:
                        task.on_error(EyesError("Render time out"))
                    else:
                        rendering.append(task)
                else:
                    task.on_success(status)
            status_tasks = rendering
            if status_tasks:
                datetime_utils.sleep(1000, "Render status polling delay")
Exemplo n.º 5
0
 def _run_render_requests(self):
     while True:
         with self._have_render_tasks:
             while not (self._shutdown or self._render_tasks):
                 self._have_render_tasks.wait()
             if self._shutdown:
                 break
             render_tasks, self._render_tasks = self._render_tasks, []
         requests = [r.request for r in render_tasks]
         logger.debug("render call with requests: {}".format(requests))
         try:
             responses = self._server_connector.render(*requests)
         except Exception as e:
             for task in render_tasks:
                 task.on_error(e)
             continue
         statuses = []
         for task, r in zip(render_tasks, responses):
             if (r.render_status == RenderStatus.NEED_MORE_RESOURCE
                     or r.need_more_dom):
                 task.on_error(EyesError("Some resources aren't uploaded"))
             else:
                 statuses.append(
                     _Status(r.render_id, task.on_success, task.on_error))
         with self._have_status_tasks:
             self._status_tasks.extend(statuses)
             self._have_status_tasks.notify()
Exemplo n.º 6
0
    def perform(self):
        # type: () -> RenderStatusResults

        def get_and_put_resource(url):
            # type: (str) -> VGResource
            resource = self.request_resources.get(url)
            self.eyes_connector.render_put_resource(running_render, resource)
            return resource

        requests = []
        rq = self.prepare_data_for_rg(self.script)
        requests.append(rq)
        fetch_fails = 0
        render_requests = None
        while True:

            try:
                render_requests = self.eyes_connector.render(*requests)
            except Exception as e:
                logger.exception(e)
                fetch_fails += 1
                time.sleep(1.5)
            if not render_requests:
                continue

            running_render = render_requests[0]
            rq.render_id = running_render.render_id
            need_more_dom = running_render.need_more_dom
            need_more_resources = (
                running_render.render_status == RenderStatus.NEED_MORE_RESOURCE
            )
            still_running = (
                need_more_resources
                or need_more_dom
                or fetch_fails > self.MAX_FAILS_COUNT
            )

            dom_resource = rq.dom.resource

            if need_more_resources:
                for url in running_render.need_more_resources:
                    self.put_cache.fetch_and_store(url, get_and_put_resource)

            if need_more_dom:
                self.eyes_connector.render_put_resource(running_render, dom_resource)

            if not still_running:
                break

        statuses = self.poll_render_status(rq)
        if statuses and statuses[0].status == RenderStatus.ERROR:
            raise EyesError(
                "Render failed for {} with the message: {}".format(
                    statuses[0].status, statuses[0].error
                )
            )
        return statuses[0]
Exemplo n.º 7
0
 def render_status(self):
     # type: ()->RenderStatusResults
     status = self._render_statuses.get(self._current_uuid)
     logger.debug("task.uuid: {}, status: {}".format(
         self._current_uuid, status))
     if not status:
         raise EyesError("Got empty render status with key {}!".format(
             self._current_uuid))
     return status
Exemplo n.º 8
0
    def prepare_rg_requests(self, dom, request_resources):
        # type: (RGridDom, Dict) -> List[RenderRequest]
        if self.size_mode == "region" and self.region_to_check is None:
            raise EyesError("Region to check should be present")
        if self.size_mode == "selector" and not isinstance(
                self.selector, VisualGridSelector):
            raise EyesError("Selector should be present")

        requests = []
        region = None
        for running_test in self.running_tests:
            if self.region_to_check:
                region = dict(
                    x=self.region_to_check.x,
                    y=self.region_to_check.y,
                    width=self.region_to_check.width,
                    height=self.region_to_check.height,
                )
            r_info = RenderInfo.from_(
                size_mode=self.size_mode,
                selector=self.selector,
                region=region,
                render_browser_info=running_test.browser_info,
            )

            requests.append(
                RenderRequest(
                    webhook=self.rendering_info.results_url,
                    agent_id=self.agent_id,
                    url=dom.url,
                    stitching_service=self.rendering_info.
                    stitching_service_url,
                    dom=dom,
                    resources=request_resources,
                    render_info=r_info,
                    browser_name=running_test.browser_info.browser,
                    platform_name=running_test.browser_info.platform,
                    script_hooks=self.script_hooks,
                    selectors_to_find_regions_for=list(
                        chain(*self.region_selectors)),
                    send_dom=running_test.configuration.send_dom,
                    options=self.request_options,
                ))
        return requests
Exemplo n.º 9
0
 def get_current_position(self):
     # type: () -> Point
     """
     The scroll position of the current frame.
     """
     if self._driver.is_mobile_web:
         x, y = self._driver.execute_script(
             self._JS_GET_CURRENT_SCROLL_POSITION, self._scroll_root_element
         )
         if x is None or y is None:
             raise EyesError("Got None as scroll position! ({},{})".format(x, y))
         return Point(x, y)
     return self.get_current_position_static(self._driver, self._scroll_root_element)
Exemplo n.º 10
0
 def get_script_result(self, dont_fetch_resources):
     # type: (bool) -> Dict
     logger.debug("get_script_result(dont_fetch_resources={})".format(
         dont_fetch_resources))
     try:
         return dom_snapshot_script.create_dom_snapshot(
             self.driver,
             dont_fetch_resources,
             None,
             DOM_EXTRACTION_TIMEOUT,
             self.configure.enable_cross_origin_rendering,
         )
     except dom_snapshot_script.DomSnapshotFailure as e:
         raise_from(EyesError("Failed to capture dom snapshot"), e)
Exemplo n.º 11
0
    def prepare_rg_requests(self, running_test, dom, request_resources):
        # type: (RunningTest, RGridDom, Dict) -> RenderRequest
        if self.size_mode == "region" and self.region_to_check is None:
            raise EyesError("Region to check should be present")
        if self.size_mode == "selector" and not isinstance(
                self.selector, VisualGridSelector):
            raise EyesError("Selector should be present")

        region = None
        if self.region_to_check:
            region = dict(
                x=self.region_to_check.x,
                y=self.region_to_check.y,
                width=self.region_to_check.width,
                height=self.region_to_check.height,
            )
        r_info = RenderInfo(
            width=running_test.browser_info.width,
            height=running_test.browser_info.height,
            size_mode=self.size_mode,
            selector=self.selector,
            region=region,
            emulation_info=running_test.browser_info.emulation_info,
        )
        return RenderRequest(
            webhook=self.rendering_info.results_url,
            agent_id=self.agent_id,
            url=dom.url,
            dom=dom,
            resources=request_resources,
            render_info=r_info,
            browser_name=running_test.browser_info.browser_type,
            platform=running_test.browser_info.platform,
            script_hooks=self.script_hooks,
            selectors_to_find_regions_for=list(chain(*self.region_selectors)),
            send_dom=running_test.configuration.send_dom,
        )
Exemplo n.º 12
0
    def check(self, name, check_settings):
        # type: (Text, SeleniumCheckSettings) -> MatchResult
        """
        Takes a snapshot and matches it with the expected output.

        :param name: The name of the tag.
        :param check_settings: target which area of the window to check.
        :return: The match results.
        """
        if self.configuration.is_disabled:
            return MatchResult()
        if not self.is_opened:
            self.abort()
            raise EyesError("you must call open() before checking")
        return self._current_eyes.check(name, check_settings)
Exemplo n.º 13
0
def create_position_provider(driver, stitch_mode, scroll_root_element,
                             target_element):
    # type: (EyesWebDriver,StitchMode,EyesWebElement,Optional[EyesWebElement])->PositionProvider
    logger.debug(
        "initializing position provider. stitch_mode: {}".format(stitch_mode))
    if stitch_mode == StitchMode.Scroll:
        return ScrollPositionProvider(driver, scroll_root_element)
    elif stitch_mode == StitchMode.CSS:
        if (driver.user_agent.os == OSNames.IOS
                and driver.user_agent.browser == BrowserNames.MobileSafari):
            return CSSMobileSafariPositionProvider(driver, scroll_root_element,
                                                   target_element)
        return CSSTranslatePositionProvider(driver, scroll_root_element)
    else:
        raise EyesError("Wrong sitch_mode")
Exemplo n.º 14
0
    def _init_driver(self, driver):
        # type: (AnyWebDriver) -> None
        if isinstance(driver, EyesWebDriver):
            # If the driver is an EyesWebDriver (as might be the case when tests are ran
            # consecutively using the same driver object)
            self._driver = driver
        else:
            self._driver = EyesWebDriver(driver, self)

        if self._driver.is_mobile_app and not isinstance(driver, AppiumWebDriver):
            logger.error("To test a mobile app you need to use appium webdriver")
            if Feature.SCALE_MOBILE_APP in self.configure.features:
                raise EyesError(
                    "For mobile app testing the appium driver should be used"
                )
Exemplo n.º 15
0
    def check(self, check_settings, name=None):
        if isinstance(name, SeleniumCheckSettings) or isinstance(
                check_settings, basestring):
            check_settings, name = name, check_settings
        if check_settings is None:
            check_settings = Target.window()
        if name:
            check_settings = check_settings.with_name(name)

        if self.configure.is_disabled:
            logger.info("check(): ignored (disabled)")
            return MatchResult()
        if not self.is_open:
            self.abort()
            raise EyesError("you must call open() before checking")
        return self._current_eyes.check(check_settings)
Exemplo n.º 16
0
 def _close(self, raise_ex, wait_result):
     # type: (bool, bool) -> Optional[TestResults]
     if self.configure.is_disabled:
         return None
     if not self.is_open:
         raise EyesError("Eyes not open")
     results = self._commands.eyes_close_eyes(self._eyes_ref, wait_result)
     self._eyes_ref = None
     self._driver = None
     if wait_result:
         results = demarshal_test_results(results, self.configure)
         for r in results:
             log_session_results_and_raise_exception(raise_ex, r)
         return results[0]  # Original interface returns just one result
     else:
         return None
Exemplo n.º 17
0
    def close(self, raise_ex=True):  # noqa
        # type: (Optional[bool]) -> Optional[TestResults]
        if self.configuration.is_disabled:
            logger.debug("close(): ignored (disabled)")
            return TestResults()
        if not self.test_list:
            return TestResults()
        logger.debug("VisualGridEyes.close()\n\t test_list %s" %
                     self.test_list)
        self.close_async()

        while True:
            states = list(set([t.state for t in self.test_list]))
            if len(states) == 1 and states[0] == "completed":
                break
            datetime_utils.sleep(500)

        self._is_opened = False

        for test in self.test_list:
            if test.pending_exceptions:
                raise EyesError(
                    "During test execution above exception raised. \n {:s}".
                    join(str(e) for e in test.pending_exceptions))
        if raise_ex:
            for test in self.test_list:
                if test.test_result is None:
                    raise TestFailedError("Test haven't finished correctly")
                results = test.test_result
                scenario_id_or_name = results.name
                app_id_or_name = results.app_name
                if results.is_unresolved and not results.is_new:
                    raise DiffsFoundError(results, scenario_id_or_name,
                                          app_id_or_name)
                if results.is_new:
                    raise NewTestError(results, scenario_id_or_name,
                                       app_id_or_name)
                if results.is_failed:
                    raise TestFailedError(results, scenario_id_or_name,
                                          app_id_or_name)

        all_results = [t.test_result for t in self.test_list if t.test_result]
        if not all_results:
            return TestResults()
        return all_results[0]
Exemplo n.º 18
0
 def get_all_test_results(self,
                          should_raise_exception=True,
                          timeout=DEFAULT_ALL_TEST_RESULTS_TIMEOUT):
     # type: (bool, Optional[int]) -> TestResultsSummary
     try:
         results = self._commands.manager_close_all_eyes(self._ref, timeout)
     except TimeoutError:
         raise EyesError(
             "Tests didn't finish in {} seconds".format(timeout))
     # We don't have server_url, api_key and proxy settings in runner
     # USDK should return them back as a part of TestResults
     structured_results = demarshal_test_results(results, None)
     for r in structured_results:
         log_session_results_and_raise_exception(should_raise_exception, r)
     return TestResultsSummary([
         TestResultContainer(result, None, None)
         for result in structured_results
     ])
Exemplo n.º 19
0
    def _set_viewport_size(self):
        viewport_size = self.configure.viewport_size

        if viewport_size is None:
            for render_bi in self.configure.browsers_info:
                if not render_bi.emulation_info:
                    viewport_size = RectangleSize(render_bi.width, render_bi.height)
                    break

        if viewport_size is None:
            viewport_size = self._get_viewport_size()

        self.configure.viewport_size = viewport_size
        try:
            eyes_selenium_utils.set_viewport_size(self.driver, viewport_size)
        except Exception as e:
            logger.exception(e)
            raise EyesError(str(e))
Exemplo n.º 20
0
 def poll_render_status(self, requests):
     # type: (List[RenderRequest]) -> List[RenderStatusResults]
     logger.debug("poll_render_status call with Requests {}".format(requests))
     iterations = 0
     statuses = []  # type: List[RenderStatusResults]
     fails_count = 0
     finished = False
     while True:
         if finished:
             break
         while True:
             try:
                 statuses = self.eyes_connector.render_status_by_id(
                     *[rq.render_id for rq in requests]
                 )
             except Exception as e:
                 logger.exception(e)
                 datetime_utils.sleep(
                     1000, msg="/render-status throws exception... sleeping for 1s"
                 )
                 fails_count += 1
             finally:
                 iterations += 1
                 datetime_utils.sleep(1500, msg="Rendering...")
             if iterations > self.MAX_ITERATIONS:
                 raise EyesError(
                     "Max iterations in poll_render_status has been reached "
                     "for render_id: \n {}".format(
                         "\n".join(s.render_id for s in statuses)
                     )
                 )
             if statuses or 0 < fails_count < 3:
                 break
         finished = bool(
             statuses
             and (
                 all(s.status != RenderStatus.RENDERING for s in statuses)
                 or iterations > self.MAX_ITERATIONS
                 or False
             )
         )
     return statuses
def set_viewport_size(driver, required_size):  # noqa
    # type: (AnyWebDriver, ViewPort) -> None
    actual_viewport_size = get_viewport_size(driver)
    if actual_viewport_size != required_size:
        actual_viewport_size = set_browser_size_by_viewport_size(
            driver, actual_viewport_size, required_size)
        if actual_viewport_size != required_size:
            # Additional attempt. This Solves the "non-resizable maximized browser" case
            # Attempt to fix it by minimizing window and retrying again
            logger.info("Trying workaround with minimization...")
            try:
                driver.minimize_window()
                actual_viewport_size = set_browser_size_by_viewport_size(
                    driver, actual_viewport_size, required_size)
            except WebDriverException:
                logger.warning("minimize_window failed")
            if actual_viewport_size != required_size:
                raise EyesError("Failed to set the viewport size.")
    else:
        logger.info("Required viewport size is already set")
    def _set_viewport_size(self):
        viewport_size = self.configure.viewport_size

        if viewport_size is None:
            for render_bi in self.configure.browsers_info:
                if isinstance(render_bi, DesktopBrowserInfo) or isinstance(
                        render_bi, RenderBrowserInfo):
                    viewport_size = render_bi.viewport_size
                    break

        if viewport_size is None:
            self.configure.viewport_size = self._get_viewport_size()
            return

        self.configure.viewport_size = viewport_size
        try:
            eyes_selenium_utils.set_viewport_size(self.driver, viewport_size)
        except Exception as e:
            logger.exception(e)
            raise EyesError(str(e))
Exemplo n.º 23
0
    def _set_viewport_size(self):
        viewport_size = self.configure.viewport_size

        if viewport_size is None:
            for render_bi in self.configure.browsers_info:
                if isinstance(render_bi,
                              (DesktopBrowserInfo, RenderBrowserInfo)):
                    viewport_size = render_bi.viewport_size
                    break

        if viewport_size is None:
            self.configure.viewport_size = self._get_viewport_size()
            return

        self.configure.viewport_size = viewport_size
        try:
            eyes_selenium_utils.set_viewport_size(self.driver, viewport_size)
        except Exception as e:
            self.logger.exception("set_viewport_size failure")
            raise_from(EyesError("Failed to set viewport size"), e)
Exemplo n.º 24
0
 def get_script_result(self):
     # type: () -> Dict
     script_response = {}
     status = None
     timer = self._start_timer()
     while True:
         if status == "SUCCESS" or self.is_check_timer_timeout:
             self.is_check_timer_timeout = False
             break
         script_result_string = self.driver.execute_script(
             PROCESS_RESOURCES + "return __processPageAndPoll();")
         try:
             script_response = json.loads(script_result_string,
                                          object_pairs_hook=OrderedDict)
             status = script_response.get("status")
         except Exception as e:
             logger.exception(e)
     timer.cancel()
     script_result = script_response.get("value")
     if script_result is None or status == "ERROR":
         raise EyesError("Failed to capture script_result")
     return script_result
Exemplo n.º 25
0
    def check(self, check_settings, name=None):
        # type: (SeleniumCheckSettings, Optional[Text]) -> Optional[MatchResult]
        if isinstance(name, SeleniumCheckSettings) or isinstance(
            check_settings, string_types
        ):
            check_settings, name = name, check_settings
        if check_settings is None:
            check_settings = Target.window()
        if name:
            check_settings = check_settings.with_name(name)

        if self.configure.is_disabled:
            return None
        if not self.is_open:
            self.abort()
            raise EyesError("you must call open() before checking")

        results = self._commands.eyes_check(
            self._eyes_ref,
            marshal_check_settings(_is_selenium_driver(self.driver), check_settings),
            self._marshaled_configuration(),
        )
        if results:
            results = demarshal_match_result(results)
            if (
                not results.as_expected
                and self.configure.failure_reports is FailureReports.IMMEDIATE
            ):
                raise TestFailedError(
                    "Mismatch found in '{}' of '{}'".format(
                        self.configure.test_name, self.configure.app_name
                    )
                )
            else:
                return results
        else:
            return None
Exemplo n.º 26
0
def get_dom_script_result(driver, dom_extraction_timeout, timer_name,
                          script_for_run):
    # type: (AnyWebDriver, int, Text, Text) -> Dict
    is_check_timer_timeout = []
    script_response = {}
    status = None

    def start_timer():
        def set_timer():
            is_check_timer_timeout.append(True)

        timer = threading.Timer(datetime_utils.to_sec(dom_extraction_timeout),
                                set_timer)
        timer.daemon = True
        timer.setName(timer_name)
        timer.start()
        return timer

    timer = start_timer()
    while True:
        if status == "SUCCESS" or is_check_timer_timeout:
            del is_check_timer_timeout[:]
            break
        script_result_string = driver.execute_script(script_for_run)
        try:
            script_response = json.loads(script_result_string,
                                         object_pairs_hook=OrderedDict)
            status = script_response.get("status")
        except Exception as e:
            logger.exception(e)
        datetime_utils.sleep(1000, "Waiting for the end of DOM extraction")
    timer.cancel()
    script_result = script_response.get("value")
    if script_result is None or status == "ERROR":
        raise EyesError("Failed to capture script_result")
    return script_result
Exemplo n.º 27
0
 def default_content_scroll_position(self):
     # type: () -> tp.Union[Point, EyesError]
     if len(self) == 0:
         raise EyesError("No frames in frame chain")
     result = self[0].parent_scroll_position
     return Point(result.x, result.y)
 def _validate_frame_window(self):
     # type: () -> None
     if self.frame_window.width <= 0 or self.frame_window.height <= 0:
         raise EyesError("Got empty frame window for screenshot!")
Exemplo n.º 29
0
    def perform(self):  # noqa
        # type: () -> List[RenderStatusResults]

        def get_and_put_resource(url, running_render):
            # type: (str, RunningRender) -> VGResource
            logger.debug(
                "get_and_put_resource({0}, render_id={1}) call".format(
                    url, running_render.render_id))
            resource = self.full_request_resources.get(url)
            self.eyes_connector.render_put_resource(running_render, resource)
            return resource

        requests = self.prepare_data_for_rg(self.script)
        fetch_fails = 0
        render_requests = None
        already_force_putted = False
        while True:
            try:
                self.put_cache.process_all()
                render_requests = self.eyes_connector.render(*requests)
            except Exception:
                logger.exception(
                    "During rendering for requests {}".format(requests))
                fetch_fails += 1
                datetime_utils.sleep(
                    1500, msg="/render throws exception... sleeping for 1.5s")
            if fetch_fails > self.MAX_FAILS_COUNT:
                raise EyesError(
                    "Render is failed. Max count retries reached for {}".
                    format(requests))
            if not render_requests:
                logger.error("running_renders is null")
                continue
            need_more_dom = need_more_resources = False
            for i, running_render in enumerate(render_requests):
                requests[i].render_id = running_render.render_id
                need_more_dom = running_render.need_more_dom
                need_more_resources = (running_render.render_status ==
                                       RenderStatus.NEED_MORE_RESOURCE)
                get_and_put_resource_wtih_render = partial(
                    get_and_put_resource, running_render=running_render)
                dom_resource = requests[i].dom.resource

                if self.is_force_put_needed and not already_force_putted:
                    for url in self.full_request_resources:
                        self.put_cache.fetch_and_store(
                            url, get_and_put_resource_wtih_render, force=True)
                    already_force_putted = True

                if need_more_resources:
                    for url in running_render.need_more_resources:
                        self.put_cache.fetch_and_store(
                            url, get_and_put_resource_wtih_render)

                if need_more_dom:
                    self.eyes_connector.render_put_resource(
                        running_render, dom_resource)
            still_running = (need_more_resources or need_more_dom
                             or fetch_fails > self.MAX_FAILS_COUNT)
            if not still_running:
                break

        return self.poll_render_status(requests)
Exemplo n.º 30
0
def set_viewport_size(driver, required_size):  # noqa
    # type: (AnyWebDriver, ViewPort) -> None
    actual_viewport_size = get_viewport_size(driver)
    if actual_viewport_size == required_size:
        logger.info("Required viewport size already set")
        return None
    logger.info(
        "Actual Viewport Size: {}\n\tTrying to set viewport size to: {}".
        format(str(actual_viewport_size), str(required_size)))

    try:
        # We move the window to (0,0) to have the best chance to be able to
        # set the viewport size as requested.
        driver.set_window_position(0, 0)
    except WebDriverException:
        logger.warning("Failed to move the browser window to (0,0)")
    if set_browser_size_by_viewport_size(driver, actual_viewport_size,
                                         required_size):
        return None

    # Additional attempt. This Solves the "maximized browser" bug
    # (border size for maximized browser sometimes different than
    # non-maximized, so the original browser size calculation is
    # wrong).
    logger.info("Trying workaround for maximization...")
    if set_browser_size_by_viewport_size(driver, actual_viewport_size,
                                         required_size):
        return None

    width_diff = abs(actual_viewport_size["width"] - required_size["width"])
    width_step = -1 if width_diff > 0 else 1  # -1 for smaller size, 1 for larger
    height_diff = abs(actual_viewport_size["height"] - required_size["height"])
    height_step = -1 if height_diff > 0 else 1

    browser_size = get_window_size(driver)
    curr_width_change = 0
    curr_height_change = 0

    if width_diff <= _MAX_DIFF and height_diff <= _MAX_DIFF:
        logger.info("Trying workaround for zoom...")
        last_required_browser_size = None

        while (abs(curr_width_change) <= width_diff
               and abs(curr_height_change) <= height_diff):
            if abs(curr_width_change) <= width_diff:
                curr_width_change += width_step
            if abs(curr_height_change) <= height_diff:
                curr_height_change += height_step

            required_browser_size = dict(
                width=browser_size["width"] + curr_width_change,
                height=browser_size["height"] + curr_height_change,
            )
            if required_browser_size == last_required_browser_size:
                logger.info(
                    "Browser size is as required but viewport size does not match!"
                )
                logger.info("Browser size: {}, Viewport size: {}".format(
                    required_browser_size, actual_viewport_size))
                logger.info("Stopping viewport size attempts.")
                break

            set_browser_size(driver, required_browser_size)
            last_required_browser_size = required_browser_size

            actual_viewport_size = get_viewport_size(driver)
            logger.info(
                "Current viewport size: {}".format(actual_viewport_size))

            if actual_viewport_size == required_size:
                return None
        else:
            logger.info("Zoom workaround failed.")

    # Attempt to fix by minimizing window
    logger.info("Trying workaround for minimization...")
    try:
        # some webdriver's don't support minimize_window
        driver.minimize_window()
    except WebDriverException as e:
        logger.exception(e)
    if set_browser_size_by_viewport_size(driver, actual_viewport_size,
                                         required_size):
        return None
    logger.error("Minimization workaround failed.")
    raise EyesError("Failed to set the viewport size.")