Test các gesture phức tạp là nơi flaky “sinh sôi” nhanh nhất: drag/drop lệch 1px, pinch-zoom lúc nhận lúc không, multi-touch bị hệ điều hành “nuốt”, chạy local thì ổn nhưng lên CI/device farm lại đỏ 🤖.
Bài này tập trung vào chiến lược thực chiến để giảm flaky khi test:
🖐️ Drag / Drop (kéo-thả)
🔍 Pinch-Zoom (phóng-thu)
🤏 Multi-touch (2+ ngón, rotate, pan + zoom đồng thời)
⏱️ Timing: animation, inertia, scroll physics
📍 Tọa độ: scale, safe area, notch, density, orientation
🧠 Trạng thái: gesture recognizer, hit-test, z-index, overlay, loading
Chỉ cần 1 trong 3 yếu tố lệch nhẹ là:
kéo không “bắt” đúng view
drop rơi sai vùng
pinch bị hiểu thành scroll / double tap
multi-touch bị mất 1 pointer
🤖 FPS thấp hơn → animation lâu hơn
📶 độ trễ input cao hơn
📱 kích thước màn hình khác
⚡ chạy song song làm hệ thống bận → event bị trễ
Không sleep(500ms) để “cho chắc”. Hãy chờ:
spinner/overlay biến mất
view stable (không layout lại)
drag handle “ready”
zoom scale đạt giá trị mong muốn (hoặc trong khoảng)
Dùng accessibilityId / testId cho:
drag handle
drop zone
canvas container
zoom indicator (nếu có)
Gesture mang tính analog → đừng assert kiểu “bằng đúng 1 giá trị”.
ví dụ zoom scale: chấp nhận 1.95–2.05 thay vì đúng 2.00
vị trí drop: chấp nhận trong bounding box thay vì đúng tọa độ tuyệt đối
Tạo helper chuẩn hoá: drag(from,to), pinch(center, scale), twoFingerPan(...)
→ giảm sai khác giữa test, dễ fix tập trung.
drag bắt nhầm view (hit-test sai)
drop “không thả” do chưa hover đủ lâu
scroll container tự cuộn khi kéo gần mép
drag bị hủy bởi animation/layout update
(1) Drag từ “handle” thay vì kéo cả item
item có thể có vùng click/scroll; handle ổn định hơn.
(2) Chia drag thành 3 pha rõ ràng
press & hold (đợi “drag mode” bật: rung/alpha/ghost)
move theo đường đi
release + chờ “drop completed” (UI state thay đổi)
(3) Tránh kéo sát mép màn hình
mép dễ kích hoạt auto-scroll / edge gestures của OS.
(4) Xác nhận “drop zone ready” trước khi thả
drop zone highlight / counter / label “Drop here”.
(5) Assert theo kết quả business
ví dụ item xuất hiện trong list đích, count tăng, trạng thái lưu thành công
→ đừng chỉ assert “tọa độ item”.
pinch bị hiểu thành scroll
hai ngón không đồng bộ → scale nhảy
zoom có inertia → assert quá sớm
zoom giới hạn min/max khác giữa device
(1) Pinch quanh một “center” ổn định
center = giữa canvas/container, tránh vùng có gesture khác (map, scroll).
(2) Chạy pinch theo bước nhỏ (multi-step)
thay vì scale x2 ngay lập tức, chia 4–6 bước
→ giảm rủi ro mất pointer.
(3) Chờ “zoom settle”
đợi animation/inertia kết thúc (scale ổn định trong N ms).
(4) Assert theo khoảng
scale trong khoảng, hoặc UI indicator hiển thị đúng mức zoom.
(5) Khóa các yếu tố gây nhiễu
tắt double-tap-to-zoom trong test build (nếu có)
tắt/giảm animation (test mode)
mất 1 ngón giữa chừng (pointer drop)
OS gesture cạnh màn hình “cướp” input
UI thread bận → event delay → recognizer reset
rotate/pinch/scroll tranh chấp nhau
(1) Test từng gesture đơn trước, rồi mới test “kết hợp”
pinch riêng ✅, pan riêng ✅, rotate riêng ✅
→ sau đó mới pan+zoom, rotate+zoom.
(2) “Gesture contract” rõ ràng trong app
Nếu bạn có thể can thiệp app:
hiển thị debug overlay: số pointer, scale, rotation, translation
expose state qua accessibility label / test API
→ test assert vào state thay vì đoán bằng mắt.
(3) Giảm mức độ “cạnh tranh gesture”
tạm disable scroll/parent gesture khi đang thao tác trên canvas
ưu tiên recognizer rõ ràng (fail-fast)
(4) Tránh edge zone
multi-touch gần cạnh rất dễ bị OS back/home gesture.
(5) Assert theo invariants
ví dụ sau pan+zoom: object vẫn nằm trong viewport, scale tăng, rotation thay đổi trong khoảng hợp lý.
Nếu team dev cho phép thêm một số hook cho build test, bạn sẽ giảm flaky rõ rệt:
🏷️ Test IDs đầy đủ cho vùng tương tác (handle/zone/canvas)
🧊 Disable/Reduce animations khi TEST_MODE=1
📐 Expose state: scale/offset/rotation (qua label hoặc debug endpoint)
🧱 Stable layout: tránh re-layout khi đang gesture
🧭 Deterministic physics: giảm inertia hoặc có “snap settle” nhanh
Gesture test ổn định không chỉ là chuyện framework; 50% là “thiết kế cho test”.
Khi fail, hãy lưu:
📸 screenshot before/after
🎥 video (rất quan trọng)
🧠 log gesture state (pointer count, scale, velocity)
📍 tọa độ start/end + bounding boxes
⏱️ timeline: lúc press, lúc move, lúc release
Sau đó phân loại:
Fail do không vào drag mode → thiếu wait/press-hold
Fail do drop không nhận → thả sớm/chưa ready
Fail do zoom chưa settle → assert quá sớm
Fail do mất pointer → bước pinch quá lớn / device lag
🔁 Không dùng sleep() bừa bãi; luôn wait theo điều kiện
🏷️ Có testId cho handle/zone/canvas
🧊 Có test mode tắt animation/giảm inertia
📍 Gesture tránh mép màn hình, tránh vùng scroll
🪜 Pinch theo step nhỏ + chờ settle
🎯 Assert theo tolerance, ưu tiên assert theo business outcome
🧰 Dùng helper gesture thống nhất toàn suite
📸 Bật video/screenshot/log cho CI
Muốn test gesture phức tạp “xanh ổn định”, hãy nhớ 3 từ khóa:
Deterministic (ổn định), Observable (đo được), Tolerant (có dung sai).
You need to login in order to like this post: click here
YOU MIGHT ALSO LIKE