def is_landscape_orientation(driver): if is_mobile_web(driver): # could be AppiumRemoteWebDriver appium_driver = get_underlying_driver( driver) # type: tp.Union[AppiumWebDriver, WebDriver] try: # We must be in native context in order to ask for orientation, # because of an Appium bug. original_context = appium_driver.context if (len(appium_driver.contexts) > 1 and not original_context.uppar() == "NATIVE_APP"): appium_driver.switch_to.context("NATIVE_APP") else: original_context = None except WebDriverException: original_context = None try: orieintation = appium_driver.orientation return orieintation.lower() == "landscape" except WebDriverException: logger.warning( "Couldn't get device orientation. Assuming Portrait.") finally: if original_context is not None: appium_driver.switch_to.context(original_context) return False
def put( self, all_resources, # type: List[VGResource] server_connector, # type: ServerConnector ): # type: (...) -> None logger.debug("PutCache.put({} call".format(all_resources)) with self._lock: not_puted = [ r for r in all_resources if r.hash not in self._sent_hashes ] if not self._force_put: check_result = server_connector.check_resource_status( not_puted) resources_to_upload = [] for resource, exists in zip(not_puted, check_result): if exists: self._sent_hashes.add(resource.hash) resource.clear() continue if resource.content is None: logger.warning( "This resource was requested by server but is cleared: " "{} {}".format(resource.hash, resource.url)) else: resources_to_upload.append(resource) else: resources_to_upload = not_puted results_iterable = self._executor.map( server_connector.render_put_resource, resources_to_upload) self._sent_hashes.update(list(results_iterable)) for resource in resources_to_upload: resource.clear()
def crop_image(image, region_to_crop): # type: (Image.Image, Region) -> Image.Image argument_guard.is_a(image, Image.Image) argument_guard.is_a(region_to_crop, Region) image_region = Region.from_(image) image_region = image_region.intersect(region_to_crop) if image_region.is_size_empty: logger.warning( "requested cropped area results in zero-size image! " "Cropped not performed. Returning original image." ) return image if image_region != region_to_crop: logger.warning("requested cropped area overflows image boundaries.") cropped_image = image.crop( box=( image_region.left, image_region.top, image_region.right, image_region.bottom, ) ) return cropped_image
def get_viewport_size_or_display_size(driver): logger.debug("get_viewport_size_or_display_size()") if not is_mobile_app(driver): try: return get_viewport_size(driver) except Exception as e: logger.warning( "Failed to extract viewport size using Javascript: {}".format( str(e))) # If we failed to extract the viewport size using JS, will use the # window size instead. logger.debug("Using window size as viewport size.") window_size = get_window_size(driver) width = window_size["width"] height = window_size["height"] try: if is_landscape_orientation(driver) and height > width: height, width = width, height except WebDriverException: # Not every WebDriver supports querying for orientation. pass logger.debug("Done! Size {:d} x {:d}".format(width, height)) return RectangleSize(width=width, height=height)
def _try_hide_caret(self): if self.configuration.hide_caret: try: self.driver.execute_script( "var activeElement = document.activeElement; activeElement " "&& activeElement.blur(); return activeElement;") except WebDriverException as e: logger.warning("Cannot hide caret! \n{}".format(e))
def _try_capture_dom(self): try: dom_json = dom_capture.get_full_window_dom(self._driver) return dom_json except Exception as e: logger.warning( "Exception raising during capturing DOM Json. Passing...\n " "Got next error: {}".format(str(e))) return None
def _collect_regions(region_providers, screenshot, eyes): # type: (List[GET_REGION], EyesScreenshot, EyesBase) -> List[REGION] collected = [] # type: List[REGION] for provider in region_providers: try: regions = provider.get_regions(eyes, screenshot) collected.extend(regions) except OutOfBoundsError: logger.warning("Region was out of bounds") return collected
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 set_window_size(driver, size): # type: (AnyWebDriver, ViewPort) -> None # We move the window to (0,0) to have the best chance to set size as requested try: driver.set_window_rect(0, 0, size["width"], size["height"]) except WebDriverException: logger.warning("set_window_rect has failed, using set_window_size") try: driver.set_window_position(0, 0) except WebDriverException: logger.warning("set_window_position has failed, ignoring") driver.set_window_size(size["width"], size["height"])
def set_overflow(driver, overflow, root_element): # type: (EyesWebDriver, Text, AnyWebElement) -> Optional[Text] root_element = get_underlying_webelement(root_element) with timeout(0.1): try: return driver.execute_script( _JS_SET_OVERFLOW % (overflow, overflow), root_element) except WebDriverException as e: logger.warning("Couldn't sent overflow {} to element {}".format( overflow, root_element)) logger.exception(e) return None
def _get_entire_size(self, image, position_provider): # type: (Image, PositionProvider) -> RectangleSize try: entire_size = position_provider.get_entire_size() logger.info( "Entire size of region context: {}".format(entire_size)) except WebDriverException as e: logger.warning( "Failed to extract entire size of region context {}".format(e)) logger.debug("Using image size instead: {} x {}".format( image.width, image.height)) entire_size = RectangleSize(image.width, image.height) return entire_size
def _get_viewport_scroll_bounds(self): switch_to = self.driver.switch_to with switch_to.frames_and_back(self.original_frame_chain): try: location = ScrollPositionProvider.get_current_position_static( 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_size(location, self._get_viewport_size()) return viewport_bounds
def _try_capture_dom(self): if self.driver.is_mobile_app: # While capture dom for native apps, appium throw an exception # "Method is not implemented" which shown in output as a warning msg # and mislead users. return None try: dom_json = dom_capture.get_full_window_dom(self._driver) return dom_json except Exception: logger.warning("dom-capture script failed, skipping it", exc_info=True) return None
def _try_capture_dom(self): if self.driver.is_mobile_app: # While capture dom for native apps, appium throw an exception # "Method is not implemented" which shown in output as a warning msg # and mislead users. return None try: dom_json = dom_capture.get_full_window_dom(self._driver) return dom_json except Exception as e: logger.warning( "Exception raising during capturing DOM Json. Passing...\n " "Got next error: {}".format(str(e))) return None
def _try_post_dom_snapshot(self, dom_json): # type: (Text) -> Optional[Text] """ In case DOM data is valid uploads it to the server and return URL where it stored. """ if dom_json is None: return None try: return self._server_connector.post_dom_snapshot(dom_json) except Exception as e: logger.warning( "Couldn't send DOM Json. Passing...\n Got next error: {}". format(e)) return None
def get_viewport_size(driver): # type: (AnyWebDriver) -> RectangleSize """ Tries to get the viewport size using Javascript. If fails, gets the entire browser window size! :param driver: The webdriver to use for getting the viewport size. """ # noinspection PyBroadException try: width, height = driver.execute_script(_JS_GET_VIEWPORT_SIZE) return RectangleSize(width=width, height=height) except WebDriverException: logger.warning( "Failed to get viewport size. Only window size is available") return get_window_size(driver)
def _try_hide_caret(self): active_element = None if self.configure.hide_caret and not self.driver.is_mobile_app: try: active_element = self.driver.execute_script( "var activeElement = document.activeElement; activeElement " "&& activeElement.blur(); return activeElement;") except WebDriverException as e: logger.warning("Cannot hide caret! \n{}".format(e)) yield if self.configure.hide_caret and not self.driver.is_mobile_app: try: self.driver.execute_script("arguments[0].focus();", active_element) except WebDriverException as e: logger.warning("Cannot hide caret! \n{}".format(e))
def process_dom_snapshot_frames( dom, # type: Dict switch_to, # type : _EyesSwitchTo script, # type: DomSnapshotScript deadline_time, # type: float poll_interval_ms, # type: int chunk_byte_length, # type: int **script_args # type: Any ): # type: (...) -> None for frame in dom["crossFrames"]: selector = frame.get("selector", None) if not selector: logger.warning("cross frame with null selector") continue frame_index = frame["index"] try: with switch_to.frame_and_back( FrameLocator(frame_selector=[By.CSS_SELECTOR, selector])): frame_dom = create_cross_frames_dom_snapshots( switch_to, script, deadline_time, poll_interval_ms, chunk_byte_length, cross_origin_rendering=True, **script_args) dom.setdefault("frames", []).append(frame_dom) frame_url = frame_dom["url"] dom["cdt"][frame_index]["attributes"].append({ "name": "data-applitools-src", "value": frame_url }) logger.info( "Created cross origin frame snapshot {}".format(frame_url)) except Exception as e: logger.warning( "Failed extracting cross frame with selector {}. Reason: {!r}". format(selector, e)) for frame in dom["frames"]: if not has_cross_subframes(frame): continue selector = frame.get("selector", None) if not selector: logger.warning("inner frame with null selector") continue try: with switch_to.frame_and_back( FrameLocator(frame_selector=[By.CSS_SELECTOR, selector])): process_dom_snapshot_frames(frame, switch_to, script, deadline_time, poll_interval_ms, chunk_byte_length, **script_args) except Exception as e: logger.warning( "Failed switching to frame with selector {}. Reason: {!r}". format(selector, e))
def download_resource(self, url, cookies): # type: (Text, Dict) -> Response headers = { "Accept-Encoding": "identity", "Accept-Language": "*", } cookies = {c["name"]: c["value"] for c in cookies} if self._ua_string: headers["User-Agent"] = self._ua_string logger.debug("Fetching URL {}\nwith headers {}".format(url, headers)) timeout_sec = datetime_utils.to_sec(self._com.timeout_ms) try: return self._try_download_resources(headers, timeout_sec, url, cookies) except (requests.HTTPError, requests.ConnectionError) as e: logger.warning("Failed to download resource", url=url, exc=e) response = Response() response._content = b"" response.status_code = requests.codes.no_response return response
def __ensure_viewport_size(self): # type: () -> None """ Assign the viewport size we need to be in the default content frame. """ if not self._is_viewport_size_set: try: if self.configure.viewport_size is None: # TODO: ignore if viewport_size settled explicitly target_size = self._get_viewport_size() self.configure.viewport_size = target_size else: target_size = self.configure.viewport_size self._set_viewport_size(target_size) self._is_viewport_size_set = True except Exception as e: logger.warning("Viewport has not been setup. {}".format(e)) self._is_viewport_size_set = False raise e
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 job_info(self): # type: () -> JobInfo if self._job_info: return self._job_info logger.warning("JobInfo is empty. Calling it again") render_requests = [ RenderRequest( render_info=RenderInfo.from_( size_mode=None, region=None, selector=None, render_browser_info=self._browser_info, ), platform_name=self._browser_info.platform, browser_name=self._browser_info.browser, ) ] self._job_info = self.server_connector.job_info(render_requests)[0] return self._job_info
def _parse_and_serialize_css(node, text, minimize=False): # type: (CssNode, tp.Text, bool) -> tp.Generator def is_import_node(n): return n.type == "at-rule" and n.lower_at_keyword == "import" stylesheet = tinycss2.parse_stylesheet(text, skip_comments=True, skip_whitespace=True) for style_node in stylesheet: if is_import_node(style_node): for tag in style_node.prelude: if tag.type == "url": logger.debug("The node has import") yield CssNode.create_sub_node(parent_node=node, href=tag.value) continue try: if minimize and style_node.content: try: # remove whitespaces inside blocks style_node.content = [ tok for tok in style_node.content if tok.type != "whitespace" ] except AttributeError as e: logger.warning( "Cannot serialize item: {}, cause error: {}".format( style_node, str(e))) serialized = style_node.serialize() if minimize: serialized = (serialized.replace("\n", "").replace( "/**/", " ").replace(" {", "{")) except TypeError as e: logger.warning(str(e)) continue yield CssNode.create_serialized_node(text=serialized)
def get_css(url): if url.startswith("blob:") or url.startswith("data:"): logger.warning("Passing blob URL: {}".format(url)) return "" return requests.get(url, timeout=CSS_DOWNLOAD_TIMEOUT).text.strip()
def set_viewport_size(driver, required_size): # type: (AnyWebDriver, ViewPort) -> None logger.debug("set_viewport_size({})".format(str(required_size))) actual_viewport_size = get_viewport_size(driver) if actual_viewport_size == required_size: logger.info("Required size already set.") return None 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)") set_browser_size_by_viewport_size(driver, actual_viewport_size, required_size) actual_viewport_size = get_viewport_size(driver) if 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...") set_browser_size_by_viewport_size(driver, actual_viewport_size, required_size) actual_viewport_size = get_viewport_size(driver) logger.debug("Current viewport size: {}".format(actual_viewport_size)) if 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.") raise WebDriverException("Failed to set the viewport size.")
def save_image(image, filename): try: logger.info("Saving file: {}".format(filename)) image.save(filename) except Exception: logger.warning("Failed to save image")