diff --git a/optics_framework/api/action_keyword.py b/optics_framework/api/action_keyword.py index 728eaea1..3c8877ea 100644 --- a/optics_framework/api/action_keyword.py +++ b/optics_framework/api/action_keyword.py @@ -68,11 +68,14 @@ def _save_annotated_for_result( return element_source = getattr(result.strategy, "element_source", None) if element_source is None or not hasattr(element_source, "get_bbox_for_element"): + internal_logger.warning(f"Element source {element_source} does not support get_bbox_for_element") return bbox = element_source.get_bbox_for_element(result.value) if bbox is None: + internal_logger.debug(f"Could not get bbox for element {result.value} in {func_name}") return if screenshot_np is None: + internal_logger.debug(f"Could not get screenshot for element {result.value} in {func_name}") return framed = utils.annotate(screenshot_np.copy(), [bbox]) utils.save_screenshot( @@ -207,7 +210,7 @@ def press_element( self.driver.press_coordinates( x + int(offset_x), y + int(offset_y), event_name) else: - internal_logger.info(f"Pressing element '{element}'") + internal_logger.info(f"Pressing element '{element}' at {located}") self.driver.press_element(located, int(repeat), event_name) def press_by_percentage(self, percent_x: str, percent_y: str, repeat: str = "1", event_name: Optional[str] = None) -> None: @@ -554,7 +557,7 @@ def press_keycode(self, keycode: str, event_name: Optional[str] = None) -> None: except Exception as e: internal_logger.error(f"Error capturing screenshot: {e}") - internal_logger.info(f"Pressing keycode: {keycode}") + internal_logger.info(f"Pressing keycode: {keycode}, {event_name}") self.driver.press_keycode(keycode, event_name) diff --git a/optics_framework/common/utils.py b/optics_framework/common/utils.py index 8bf1803f..26e59bd4 100644 --- a/optics_framework/common/utils.py +++ b/optics_framework/common/utils.py @@ -175,11 +175,10 @@ def parse_text_only_prefix(element: str) -> Tuple[str, bool]: def get_timestamp(): try: - current_utc_time = datetime.now(timezone.utc) - desired_timezone = timezone(timedelta(hours=5, minutes=30)) - current_time_in_desired_timezone = current_utc_time.astimezone(desired_timezone) - formatted_time = current_time_in_desired_timezone.strftime("%Y-%m-%dT%H:%M:%S.%f%z") - return formatted_time[:-2] + ":" + formatted_time[-2:] + ist = timezone(timedelta(hours=5, minutes=30)) + now_ist = datetime.now(ist) + return now_ist.strftime("%Y-%m-%dT%H-%M-%S-%f") + except Exception as e: internal_logger.error('Unable to get current time', exc_info=e) return None @@ -273,19 +272,23 @@ def save_screenshot(img, name, output_dir, time_stamp=None): return name = re.sub(r'[^a-zA-Z0-9\s_]', '', name) if time_stamp is None: - time_stamp = str(datetime.now().astimezone().strftime('%Y-%m-%dT%H-%M-%S-%f')) + time_stamp = datetime.now().astimezone().strftime('%Y-%m-%dT%H-%M-%S-%f%z') + screenshot_file_path = os.path.join(output_dir, f"{time_stamp}-{name}.jpg") - try: - cv2.imwrite(screenshot_file_path, img) - internal_logger.debug(f'Screenshot saved as : {time_stamp}-{name}.jpg') + success = cv2.imwrite(screenshot_file_path, img) + + if success: + internal_logger.debug(f"Screenshot saved as : {time_stamp}-{name}.jpg") internal_logger.debug(f"Screenshot saved to :{screenshot_file_path}") + else: + internal_logger.error(f"cv2 returned FALSE. FAILED to save screenshot to : {screenshot_file_path}") + raise Exception(f"cv2 returned FALSE. FAILED to save screenshot to : {screenshot_file_path}") - except Exception as e: - internal_logger.debug(f"Error writing screenshot to file : {e}") def annotate(screenshot, bboxes): # Iterate over each bounding box and annotate it on the image + internal_logger.debug(f"Bounding boxes {bboxes} to be annotated.") for bbox in bboxes: if bbox is None or len(bbox) != 2: internal_logger.debug(f"Invalid bounding box: {bbox}") diff --git a/optics_framework/engines/drivers/appium.py b/optics_framework/engines/drivers/appium.py index 7b9fc1e0..64faf5ec 100644 --- a/optics_framework/engines/drivers/appium.py +++ b/optics_framework/engines/drivers/appium.py @@ -910,9 +910,13 @@ def _flush_keyboard_buffer(self, driver: WebDriver, buffer: List[str]) -> None: def _press_keycode_or_type_char(self, driver: WebDriver, ch: str, keycode: int) -> None: """Press keycode for char, or fall back to mobile:type on failure.""" - internal_logger.debug(f"Pressing keycode for char '{ch}': {keycode}") + metastate = 1 if ch.isupper() else None + internal_logger.debug(f"Pressing keycode for char '{ch}': {keycode} (metastate={metastate})") try: - driver.press_keycode(int(keycode)) + if metastate is not None: + driver.press_keycode(int(keycode), metastate=metastate) + else: + driver.press_keycode(int(keycode)) except Exception: internal_logger.debug(f"press_keycode failed for '{ch}', falling back to script typing") driver.execute_script( @@ -979,7 +983,8 @@ def get_char_as_keycode(self, char: str) -> Optional[int]: "\n": 66, # Enter key } - return mapping.get(char.lower()) # handle lowercase input + # Handle lowercase input so uppercase letters map to correct keycodes + return mapping.get(char.lower()) def get_text_element(self, element: Any) -> str: text = element.get_attribute("text") or element.get_attribute("value")