CYBERSOFT
Đăng nhập

Waits & xử lý bất đồng bộ trong automation cho người mới (có code Playwright chạy được)

Chuyên công nghệNền tảngNgười mớiChuẩn SEO
🗓 1 tháng trước19 phút đọc·👁 1,800 lượt xem👤 335 người đọc

Bài cho người mới: học cách chờ (waits) đúng thời điểm trong automation qua app TMĐT ShopEasy. Vì sao test hay 'flaky' vì thời gian, implicit vs explicit wait, auto-waiting của Playwright, cách viết await expect()/waitFor() chạy được, timeout hợp lý, hai tình huống thật (sleep cứng, click trước khi phần tử sẵn sàng), nhiều mockup giao diện, FAQ và trắc nghiệm 5 câu. Chuẩn SEO, dẫn về khóa Tester CyberSoft.

1. Tóm tắt nhanh & màn hình bạn sẽ test

⭐ TL;DR — Waits automation là kỹ năng chờ đúng thời điểm trong test tự động: thay vì đoán mò bằng sleep cứng, bạn chờ đúng điều kiện (phần tử hiện, dữ liệu tải xong) rồi mới thao tác. Bài này bám trang sản phẩm tải bất đồng bộ của ShopEasy: vì sao test hay 'flaky' do thời gian, implicit vs explicit wait, auto-wait của Playwright, và cách viết await expect()/waitFor() chạy được thật, kèm timeout hợp lý. Nhiều hình minh hoạ và trắc nghiệm cuối bài.

Chào bạn mới! Khi mới học automation, bạn sẽ sớm gặp một hiện tượng khó chịu: test chạy pass lúc này, fail lúc khác, dù bạn không hề sửa gì. Thủ phạm phổ biến nhất chính là 'thời gian' — cụ thể là việc trang web tải dữ liệu bất đồng bộ (gọi API, render danh sách sản phẩm...) mất một khoảng thời gian không cố định. Nếu script automation thao tác 'quá sớm', trước khi dữ liệu thật sự sẵn sàng, test sẽ fail dù ứng dụng hoàn toàn không có lỗi. Bài này giúp bạn hiểu đúng cơ chế 'chờ' trong automation, qua trang sản phẩm ShopEasy — nơi danh sách sản phẩm chỉ xuất hiện sau khi gọi API xong.

🔒 shopeasy.vn/san-pham ShopEasy · TMĐT ShopEasy · Trang sản phẩm (đang tải) Đang tải dữ liệu sản phẩm từ server... Locator: .product-list[data-state="loading"] — DOM đã có nhưng CHƯA đúng nội dung cần test
Màn hình test: ShopEasy đang tải dữ liệu sản phẩm bất đồng bộ, chú thích locator ở trạng thái 'đang tải'
📖 Wait (chờ): hành động khiến automation TẠM DỪNG một cách có chủ đích cho tới khi 1 điều kiện cụ thể đúng, hoặc hết thời gian timeout cho phép.

2. Vấn đề: vì sao test tự động hay 'flaky' vì thời gian

Web hiện đại hiếm khi tải xong mọi thứ ngay lập tức. Khi bạn mở trang sản phẩm ShopEasy, trình duyệt trả về khung HTML rỗng trước, rồi JavaScript mới gọi API lấy danh sách sản phẩm, và chỉ khi API trả lời xong, danh sách mới được render lên màn hình. Khoảng thời gian giữa 'mở trang' và 'dữ liệu thật sự sẵn sàng' không cố định — nó phụ thuộc tốc độ mạng, tải server, và có thể khác nhau ở mỗi lần chạy dù cùng một môi trường.

Script automation thường chạy nhanh hơn nhiều so với tốc độ con người click chuột — và đôi khi còn nhanh hơn cả tốc độ trang web render xong. Nếu script viết '.product-item' ngay sau page.goto(), có khả năng thật cao là lúc đó server vẫn đang xử lý response, danh sách sản phẩm chưa hề tồn tại trên DOM. Kết quả: test báo lỗi 'element not found', dù chỉ vài trăm mili-giây sau đó, phần tử này xuất hiện hoàn toàn bình thường. Đây chính là bản chất của một race condition trong automation — automation 'đến trước' dữ liệu thật.

Các loại wait (chờ) phổ biến trong automation Loại waitCách hoạt độngKhi nào nên dùngSleep cứng (hard sleep)Dừng đúng N giây bất kể trang đã sẵn sàng hay chưaGần như không nên dùng — nguồn gây flaky hàng đầuImplicit waitCấu hình 1 lần cho cả trình duyệt, áp dụng ngầm cho mọi lần tìm phần tửSelenium truyền thống; kém linh hoạt, khó đoán khi trộn nhiều điều kiệnExplicit waitChờ đến khi ĐÚNG 1 điều kiện cụ thể xảy ra, đặt ngay tại chỗ cầnKhi cần chờ đúng điều kiện nghiệp vụ (dữ liệu tải xong, nút bật lại...)Auto-wait (Playwright)Tự động chờ phần tử 'actionable' trước mỗi hành động, không cần viết wait tayMặc định cho hầu hết click/fill/hover trong Playwright hiện đạiPolling / waitFor tuỳ biếnLặp kiểm tra 1 hàm điều kiện tới khi đúng hoặc hết timeoutĐiều kiện phức tạp, không có sẵn assertion dựng sẵnCùng mục tiêu 'chờ đúng lúc', nhưng độ tin cậy và chi phí bảo trì rất khác nhau.
Bảng tổng hợp các loại wait phổ biến trong automation và khi nào nên dùng
📖 Flaky test: một test đôi khi pass, đôi khi fail dù code test và ứng dụng không hề đổi giữa các lần chạy — nguyên nhân phổ biến nhất là chờ sai thời điểm.

3. Sleep cứng (hard sleep) — vì sao là cách tệ nhất

Phản xạ tự nhiên của người mới khi gặp lỗi 'element not found' là thêm một dòng dừng cứng: page.waitForTimeout(2000) — chờ đúng 2 giây rồi mới thao tác tiếp. Cách này có vẻ giải quyết được vấn đề trước mắt, nhưng thực chất chỉ đang 'đoán mò' một con số, không hề dựa vào trạng thái thực tế của trang. Vấn đề lộ ra ngay khi tốc độ hệ thống thay đổi — mà điều này gần như chắc chắn sẽ xảy ra giữa các lần chạy khác nhau.

🎯 🎯 Tình huống: Một tester mới viết test cho trang sản phẩm ShopEasy, thêm page.waitForTimeout(2000) ngay sau khi mở trang, rồi mới đọc '.product-item' để kiểm tra sản phẩm hiển thị đúng.

Ở máy cá nhân, mạng nhanh, API trả lời trong 400ms — test luôn pass, nhưng lãng phí gần 1.6 giây chờ vô ích mỗi lần chạy. Khi đẩy lên CI chạy song song nhiều test cùng lúc, server chịu tải cao hơn, API đôi khi mất tới 2.5 giây mới trả lời. Lúc đó test vẫn thao tác đúng sau 2 giây như đã hẹn — nhưng dữ liệu thật sự CHƯA có, và test fail với lỗi 'element not found', dù trang sản phẩm hoàn toàn không có lỗi.

✅ Cách giải: Thay page.waitForTimeout(2000) bằng await expect(page.locator('.product-item').first()).toBeVisible() — chờ ĐÚNG điều kiện 'sản phẩm đầu tiên đã hiển thị', bất kể API trả lời trong 400ms hay 2.5 giây. Test chạy nhanh khi hệ thống nhanh, và vẫn đúng khi hệ thống chậm hơn bình thường một chút.
Sleep cứng vs chờ theo điều kiện (chờ đúng lúc) Tiêu chíSleep cứng (waitForTimeout)Chờ theo điều kiện (expect/waitFor)Khi trang tải NHANH hơn thời gian chờLãng phí thời gian chờ thừa, test chạy chậm không cần thiếtĐi tiếp ngay khi điều kiện đúng, không phí giây nàoKhi trang tải CHẬM hơn thời gian chờThao tác quá sớm, phần tử chưa sẵn sàng — test fail dù app không lỗiTiếp tục chờ tới khi đúng điều kiện hoặc hết timeout hợp lýĐộ ổn định (ít flaky)Thấp — phụ thuộc con số đoán mò, không phản ánh thực tế mạng/serverCao — bám sát trạng thái thật của trang tại mọi lần chạyChi phí bảo trìPhải chỉnh số giây thủ công mỗi khi tốc độ hệ thống đổiKhông cần chỉnh — điều kiện tự thích ứng với tốc độ thực tếThời gian chạy toàn bộ suiteCộng dồn thời gian chờ thừa ở hàng trăm testChỉ chờ đúng phần cần, tổng thời gian chạy nhanh hơn rõ rệtSleep cứng là con dao hai lưỡi: không bao giờ vừa đủ cho mọi lần chạy.
Bảng so sánh sleep cứng và chờ theo điều kiện ở cả hai kịch bản: hệ thống nhanh và hệ thống chậm
! Bug · SE-14107 JIRA Test 'hien-thi-danh-sach-san-pham' flaky: pass khi mạng nhanh, fail khi mạng chậm STATUS: Open PRIORITY: High SEVERITY: Medium Môi trườngstaging · web ShopEasy · Chrome 126 · CI pipeline chạy song songNguyên nhânTest dùng page.waitForTimeout(2000) trước khi đọc '.product-item', trong khi API sản phẩm đôi khi mất hơn 2.5s ở môi trường CI tải caoẢnh hưởngTest báo fail 'element not found' dù tính năng hiển thị sản phẩm hoàn toàn đúng, làm giảm niềm tin vào bộ test tự độngĐề xuấtThay waitForTimeout(2000) bằng await expect(locator).toBeVisible() để chờ đúng điều kiện thay vì đoán số giây cố định
Ticket lỗi ghi lại sự cố flaky test do sleep cứng quá ngắn so với tốc độ thật của API
  • 📌 Sleep cứng dùng 1 con số cố định, không phản ánh tốc độ thực tế đang đổi liên tục
  • 📌 Chờ theo điều kiện luôn 'vừa đủ': nhanh thì đi ngay, chậm thì vẫn đợi đúng

4. Implicit wait là gì & vì sao có giới hạn

Implicit wait là một cấu hình đặt MỘT LẦN ở cấp trình duyệt hoặc phiên làm việc: 'nếu tìm không thấy phần tử ngay, hãy tự động thử lại trong tối đa N giây trước khi báo lỗi'. Cấu hình này áp dụng ngầm cho MỌI lần tìm phần tử trong suốt phiên, bạn không cần viết lại ở từng dòng code. Đây là cách tiếp cận phổ biến trong các công cụ automation thế hệ cũ như Selenium WebDriver truyền thống.

Giới hạn lớn nhất của implicit wait là tính 'tất cả hoặc không có gì': cùng một con số N giây áp dụng cho MỌI phần tử, dù đó là một nút bấm luôn có sẵn ngay lập tức, hay một danh sách sản phẩm cần chờ API trả lời. Nếu N quá ngắn, những phần tử cần chờ lâu vẫn fail; nếu N quá dài, mọi lần tìm phần tử không thấy (kể cả lỗi thật của ứng dụng) đều phải đợi rất lâu mới báo lỗi, làm chậm cả bộ test. Ngoài ra, khi trộn implicit wait với explicit wait, hành vi chờ có thể trở nên khó đoán, vì hai cơ chế cộng dồn lên nhau theo cách không rõ ràng.

🔒

Nội dung bị khoá

Bạn đang xem bản xem trước. Đăng nhập để mở khoá toàn bộ bài viết và tất cả tài liệu Tester/QA.

Đã xem 25% nội dung
  • Đọc trọn vẹn mọi bài viết
  • Lưu bài & ghi chú cá nhân
  • Theo dõi tiến độ đã đọc
  • Luyện phỏng vấn, ISTQB, Mock
Đăng nhập để đọc tiếp

Chưa có mã? Lấy mã qua Fanpage / Zalo CyberSoft.

0

💬 Bình luận (0)

Bạn có thể đọc mọi bình luận. Đăng nhập để bình luận

Chưa có bình luận nào. Hãy là người đầu tiên!