def configured_connector(custom_eyes_server):
    # type: (Optional[Text]) -> ServerConnector
    connector = ServerConnector()
    conf = Configuration(server_url=custom_eyes_server)
    connector.update_config(conf)
    return connector
Example #2
0
def test_check_default_server_url_from_settings():
    connector = ServerConnector()
    conf = Configuration()
    connector.update_config(conf)
    assert connector.server_url == DEFAULT_SERVER_URL
class VisualGridEyes(object):
    vg_manager = None  # type: VisualGridRunner
    _config_provider = None
    _is_opened = False
    _driver = None
    rendering_info = None
    is_check_timer_timeout = False

    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]

    @property
    def is_open(self):
        return self._is_opened

    @property
    def driver(self):
        return self._driver

    @property
    def configure(self):
        # type: () -> Configuration
        return self._config_provider.configure

    @property
    def base_agent_id(self):
        # type: () -> Text
        """
        Must return version of SDK. (e.g. selenium, visualgrid) in next format:
            "eyes.{package}.python/{lib_version}"
        """
        return "eyes.selenium.visualgrid.python/{version}".format(
            version=__version__)

    @property
    def full_agent_id(self):
        # type: () -> Text
        """
        Gets the agent id, which identifies the current library using the SDK.

        """
        agent_id = self.configure.agent_id
        if agent_id is None:
            return self.base_agent_id
        return "{} [{}]".format(agent_id, self.base_agent_id)

    def _job_info_for_browser_info(self, browser_infos):
        # type: (List[RenderBrowserInfo]) -> Generator[RenderBrowserInfo, JobInfo]
        render_requests = [
            RenderRequest(
                render_info=RenderInfo.from_(
                    size_mode=None,
                    region=None,
                    selector=None,
                    render_browser_info=b_info,
                ),
                platform_name=b_info.platform,
                browser_name=b_info.browser,
            ) for b_info in browser_infos
        ]

        job_infos = self.server_connector.job_info(render_requests)
        for b_info, job_info in zip(browser_infos, job_infos):
            yield b_info, job_info

    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

    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)

    @staticmethod
    def _options_dict(configuration_options, check_settings_options):
        return {
            o.key: o.value
            for o in itertools.chain(configuration_options or (),
                                     check_settings_options or ())
        }

    def check(self, check_settings):
        # type: (SeleniumCheckSettings) -> None
        argument_guard.is_a(check_settings, CheckSettings)
        name = check_settings.values.name
        logger.debug("VisualGridEyes.check(%s, %s)" % (name, check_settings))
        self._try_set_target_selector(check_settings)

        self.configure.send_dom = check_settings.values.send_dom

        check_settings = self._update_check_settings(check_settings)
        logger.info("check('{}', check_settings) - begin".format(name))

        region_xpaths = self.get_region_xpaths(check_settings)
        logger.info("region_xpaths: {}".format(region_xpaths))
        dont_fetch_resources = self._effective_disable_browser_fetching(
            self.configure, check_settings)
        running_tests = [
            test for test in self.test_list
            if self._test_uuid == test.test_uuid
        ]

        try:
            script_result = self.get_script_result(dont_fetch_resources)
            logger.debug("Cdt length: {}".format(len(script_result["cdt"])))
            logger.debug("Blobs urls: {}".format(
                [b["url"] for b in script_result["blobs"]]))
            logger.debug("Resources urls: {}".format(
                script_result["resourceUrls"]))
            source = eyes_selenium_utils.get_check_source(self.driver)
            checks = [
                test.check(
                    check_settings=check_settings,
                    region_selectors=region_xpaths,
                    source=source,
                ) for test in running_tests
            ]

            resource_collection_task = self._resource_collection_task(
                check_settings, region_xpaths, running_tests, script_result,
                checks)
            self.vg_manager.add_resource_collection_task(
                resource_collection_task)
        except Exception as e:
            logger.exception(e)
            for test in running_tests:
                if test.state != TESTED:
                    # already aborted or closed
                    test.abort()
                    test.becomes_tested()
        logger.info("added check tasks  {}".format(check_settings))

    def _resource_collection_task(
            self,
            check_settings,  # type: SeleniumCheckSettings
            region_xpaths,  # type: List[List[VisualGridSelector]]
            running_tests,  # type: List[RunningTest]
            script_result,  # type: Dict
            checks,  # type: List[RunningTestCheck]
    ):
        # type: (...) -> ResourceCollectionTask
        tag = check_settings.values.name
        short_description = "{} of {}".format(self.configure.test_name,
                                              self.configure.app_name)
        resource_collection_task = ResourceCollectionTask(
            name="VisualGridEyes.check-resource_collection {} - {}".format(
                short_description, tag),
            script=script_result,
            resource_cache=self.vg_manager.resource_cache,
            put_cache=self.vg_manager.put_cache,
            rendering_info=self.server_connector.render_info(),
            server_connector=self.server_connector,
            region_selectors=region_xpaths,
            size_mode=check_settings.values.size_mode,
            region_to_check=check_settings.values.target_region,
            script_hooks=check_settings.values.script_hooks,
            agent_id=self.base_agent_id,
            selector=check_settings.values.selector,
            running_tests=running_tests,
            request_options=self._options_dict(
                self.configure.visual_grid_options,
                check_settings.values.visual_grid_options,
            ),
        )

        def on_collected_task_succeeded(render_requests):
            for check in checks:
                check.set_render_request(render_requests[check.running_test])

        def on_collected_task_error(e):
            # TODO: Improve exception handling
            running_tests[0].pending_exceptions.append(e)
            for test in running_tests:
                if test.state != TESTED:
                    # already aborted or closed
                    test.abort()
                    test.becomes_tested()

        resource_collection_task.on_task_succeeded(on_collected_task_succeeded)
        resource_collection_task.on_task_error(on_collected_task_error)
        return resource_collection_task

    def close_async(self):
        for test in self.test_list:
            test.close()

    def close(self, raise_ex=True):  # noqa
        # type: (Optional[bool]) -> Optional[TestResults]
        if not self.test_list:
            return TestResults(status="Failed")
        logger.debug("VisualGridEyes.close()\n\t test_list %s" %
                     self.test_list)
        self.close_async()

        wait_till_tests_completed(self.test_list)

        self._is_opened = False

        all_results = collect_test_results(
            {t: t.test_result
             for t in self.test_list}, raise_ex)
        if not all_results:
            return TestResults(status="Failed")
        return all_results[0].test_results

    def abort_async(self):
        """
        If a test is running, aborts it. Otherwise, does nothing.
        """
        for test in self.test_list:
            test.abort()

    def abort(self):
        """
        If a test is running, aborts it. Otherwise, does nothing.
        """
        self._is_opened = False
        self.abort_async()

    def abort_if_not_closed(self):
        logger.deprecation("Use `abort()` instead")
        self.abort()

    def _update_check_settings(self, check_settings):
        # type: (SeleniumCheckSettings) -> SeleniumCheckSettings
        match_level = check_settings.values.match_level
        fully = check_settings.values.stitch_content
        send_dom = check_settings.values.send_dom
        ignore_displacements = check_settings.values.ignore_displacements

        if match_level is None:
            check_settings = check_settings.match_level(
                self.configure.match_level)
        if fully is None:
            fps = self.configure.force_full_page_screenshot
            check_settings = check_settings.fully(
                check_settings.is_check_window if fps is None else fps)
        if send_dom is None:
            send = self.configure.send_dom
            check_settings = check_settings.send_dom(
                True if send is None else send)
        if ignore_displacements is None:
            check_settings = check_settings.ignore_displacements(
                self.configure.ignore_displacements)
        return check_settings

    def _create_vgeyes_connector(self, b_info, job_info):
        # type: (RenderBrowserInfo, JobInfo) -> EyesConnector
        return EyesConnector(b_info, self.configure.clone(),
                             deepcopy(self.server_connector), job_info)

    def _try_set_target_selector(self, check_settings):
        # type: (SeleniumCheckSettings) -> None
        element = check_settings.values.target_element
        if element is None:
            target_selector = check_settings.values.target_selector
            if target_selector:
                by, value = target_selector
                element = self.driver.find_element(by, value)

        if element is None:
            return None
        element = eyes_selenium_utils.get_underlying_webelement(element)
        xpath = self.driver.execute_script(GET_ELEMENT_XPATH_JS, element)
        vgs = VisualGridSelector(xpath, "target")
        check_settings.values.selector = vgs

    def get_region_xpaths(self, check_settings):
        # type: (SeleniumCheckSettings) -> List[List[VisualGridSelector]]
        element_lists = self.collect_selenium_regions(check_settings)
        frame_chain = self.driver.frame_chain.clone()
        result = []
        for element_list in element_lists:
            xpaths = []
            for elem_region in element_list:
                if elem_region.webelement is None:
                    continue
                xpath = self.driver.execute_script(GET_ELEMENT_XPATH_JS,
                                                   elem_region.webelement)
                xpaths.append(
                    VisualGridSelector(xpath, elem_region.region_provider))
            result.append(xpaths)
        self.driver.switch_to.frames(frame_chain)
        return result

    def collect_selenium_regions(self, check_settings):
        # type: (SeleniumCheckSettings) -> List[List[WebElementRegion]]
        ignore_elements = self.get_elements_from_regions(
            check_settings.values.ignore_regions)
        layout_elements = self.get_elements_from_regions(
            check_settings.values.layout_regions)
        strict_elements = self.get_elements_from_regions(
            check_settings.values.strict_regions)
        content_elements = self.get_elements_from_regions(
            check_settings.values.content_regions)
        floating_elements = self.get_elements_from_regions(
            check_settings.values.floating_regions)
        accessibility_elements = self.get_elements_from_regions(
            check_settings.values.accessibility_regions)
        element = check_settings.values.target_element
        if element is None:
            target_selector = check_settings.values.target_selector
            if target_selector:
                by, value = target_selector
                element = self.driver.find_element(by, value)

        targets = [WebElementRegion("target", element)]
        return [
            ignore_elements,
            layout_elements,
            strict_elements,
            content_elements,
            floating_elements,
            accessibility_elements,
            targets,
        ]

    def get_elements_from_regions(self, regions_provider):
        # type:(List[GetRegion])->List[WebElementRegion]
        elements = []
        for rp in regions_provider:
            if not hasattr(rp, "get_elements"):
                continue
            webelements = rp.get_elements(self.driver)
            for elem in webelements:
                elements.append(WebElementRegion(rp, elem))
        return elements

    def _get_viewport_size(self):
        argument_guard.not_none(self.driver)
        return eyes_selenium_utils.get_viewport_size(self.driver)

    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:
            logger.exception(e)
            raise_from(EyesError("Failed to set viewport size"), e)

    @staticmethod
    def _effective_disable_browser_fetching(config, check_settings):
        if check_settings.values.disable_browser_fetching is not None:
            return check_settings.values.disable_browser_fetching
        else:
            return config.disable_browser_fetching