Khắc phục lỗi RuntimeError: call depth exceed 4 khi sử dụng AirTest Poco trên iOS

Trong quá trình thực hiện kiểm thử tự động (Automation Testing) trên iOS bằng framework AirTest và Poco, bạn có thể gặp phải lỗi hệ thống dừng đột ngột với thông báo RuntimeError: call depth exceed 4. Lỗi này thường phát sinh khi script cố gắng tương tác hoặc kiểm tra sự tồn tại của một phần tử UI nhưng gặp vấn đề trong quá trình truy xuất dữ liệu từ WebDriverAgent (WDA).

Dưới đây là chi tiết log lỗi điển hình:

File "/site-packages/poco/proxy.py", line 657, in wait
    while not self.exists():
  File "/site-packages/poco/proxy.py", line 774, in exists
    return self.attr('visible')
  File "/site-packages/poco/proxy.py", line 734, in attr
    nodes = self._do_query(multiple=False)
  File "/site-packages/poco/proxy.py", line 884, in _do_query
    self._nodes = self.poco.agent.hierarchy.select(self.query, multiple)
  File "/site-packages/poco/sdk/Selector.py", line 77, in select
    return self.selectImpl(cond, multiple, self.getRoot(), 9999, True, True)
  File "/site-packages/poco/sdk/Selector.py", line 71, in getRoot
    return self.dumper.getRoot()
  File "/site-packages/poco/drivers/ios/__init__.py", line 54, in dumpHierarchy
    jsonObj = self.client.driver.source(format='json')
  File "/site-packages/wda/__init__.py", line 464, in source
    return self.http.get('source?format=' + format).value
  File "/site-packages/wda/utils.py", line 43, in _inner
    raise RuntimeError("call depth exceed %d" % n)
RuntimeError: call depth exceed 4

Phân tích nguyên nhân gốc rễ

Vấn đề nằm ở cơ chế giao tiếp giữa thư viện Poco và driver điều khiển iOS (thường là facebook-wda). Cụ thể:

  • Khi gọi wait().exists(), Poco sẽ liên tục thực hiện dump cấu trúc UI (Hierarchy) từ thiết bị.
  • Mỗi thao tác dump sẽ gửi một yêu cầu HTTP đến WDA.
  • Trong thư viện wda, phương thức xử lý yêu cầu được bao bọc bởi một decorator có tên @limit_call_depth(4).
  • Nếu kết nối mạng không ổn định hoặc dịch vụ WDA trên iPhone phản hồi chậm, yêu cầu HTTP sẽ thất bại và kích hoạt cơ chế đệ quy để thử lại.
  • Khi số lần đệ quy vượt quá giới hạn cho phép (mặc định là 4), decorator này sẽ ném ra lỗi RuntimeError để ngăn chặn việc treo tiến trình vô hạn.

Giải pháp xử lý an toàn

Để khắc phục tình trạng này, chúng ta cần xây dựng một hàm bao bọc (wrapper) để bắt ngoại lệ và thực hiện tái thử thi với khoảng nghỉ hợp lý, giúp script hoạt động ổn định hơn.

def verify_ui_element_safe(ui_proxy, wait_time=10, max_attempts=3, retry_delay=5):
    """
    Kiểm tra sự tồn tại của phần tử Poco một cách an toàn,
    xử lý ngoại lệ 'call depth exceed' từ driver iOS.

    Args:
        ui_proxy: Đối tượng Poco proxy (ví dụ: poco("Button_Login"))
        wait_time: Thời gian chờ tối đa cho mỗi lần kiểm tra (giây)
        max_attempts: Số lần thử lại tối đa khi gặp lỗi RuntimeError
        retry_delay: Thời gian nghỉ giữa các lần thử lại (giây)

    Returns:
        bool: Trả về True nếu phần tử tồn tại, ngược lại trả về False.
    """
    for i in range(max_attempts):
        try:
            # Thực hiện kiểm tra sự tồn tại của phần tử
            return ui_proxy.wait(timeout=wait_time).exists()
        except RuntimeError as err:
            error_msg = str(err)
            if "call depth exceed" in error_msg:
                print(f"[Cảnh báo] Lỗi WDA (Attempt {i+1}/{max_attempts}): {error_msg}")
                if i < max_attempts - 1:
                    sleep(retry_delay)
                else:
                    print("[Lỗi] Đã đạt giới hạn thử lại tối đa. Bỏ qua phần tử.")
                    return False
            else:
                # Nếu là lỗi RuntimeError khác thì ném tiếp ra ngoài
                raise err
        except Exception as other_err:
            print(f"[Lỗi không xác định]: {other_err}")
            return False
    return False

Bằng cách sử dụng hàm verify_ui_element_safe thay cho lời gọi trực tiếp, script của bạn sẽ có khả năng tự phục hồi khi gặp các lỗi kết nối tạm thời với WebDriverAgent, tránh việc toàn bộ quá trình kiểm thử bị gián đoạn chỉ vì một lỗi dump UI đơn lẻ.

Thẻ: AirTest Poco iOS-Automation python facebook-wda

Đăng vào ngày 11 tháng 8 lúc 03:49