Hoot unit test kiểm một mảnh code — gọi hàm, so kết quả. Nhưng phần mềm thật hỏng ở chỗ khác: người dùng bấm nút A, điền ô B, chuyển sang màn hình C, và đâu đó trong chuỗi đó có gì sai. Kiểm cả luồng ấy cần một công cụ khác: tour. Tour là một kịch bản mô phỏng người dùng đi qua nhiều bước trên giao diện thật — Odoo bấm và điền hộ bạn, rồi báo luồng có chạy trót lọt không.
Tour: danh sách các bước trên UI thật
Một tour là một object đăng ký vào category web_tour.tours của registry, gồm url (nơi bắt đầu) và steps (mảng các bước). Mỗi bước có trigger (chờ một phần tử xuất hiện) và run (hành động: bấm, gõ chữ, hay một hàm):

Hình 1: Một tour hai bước. trigger là một selector CSS — tour chờ phần tử đó xuất hiện rồi mới tiếp (đây là cách tour đồng bộ với UI bất đồng bộ, không cần sleep). content là chú thích hiện trong bong bóng (dùng cho onboarding). run là hành động: "click", "edit <chữ>" (gõ vào ô), hay một hàm tuỳ ý. Tour đăng ký vào web_tour.tours.
Chạy thật: SUCCEEDED
Tour kích hoạt bằng odoo.startTour("tên") trong trình duyệt, hoặc trong một test Python bằng HttpCase.start_tour(url, "tên", login=...) — đó là cách CI chạy tour tự động. Mình chạy tour trên dashboard và bắt console:

Hình 2: Kết quả thật. Tour chạy qua [1/2] rồi [2/2] — mỗi dòng ghi bước và trigger đang chờ — rồi kết luận tour succeeded với khung "TOUR quan_ca_phe_tour SUCCEEDED". Nếu một trigger không bao giờ xuất hiện (vì UI hỏng), tour thất bại và báo đúng bước kẹt — đó chính là giá trị kiểm thử: nó bắt được luồng gãy ở đâu.
Tour so với Hoot unit test
Hai công cụ, hai tầng:
| Hoot unit test | Tour | |
|---|---|---|
| Kiểm cái gì | một hàm/component | cả một luồng nhiều bước |
| Chạy trên | code cô lập | UI thật, server thật |
| Nhanh/chậm | rất nhanh | chậm hơn (dựng cả app) |
| Bắt được | logic sai | tích hợp gãy, nút mất, luồng đứt |
Dùng cả hai: unit test cho phần lớn logic (nhanh, nhiều), tour cho vài luồng quan trọng (đăng ký, đặt hàng, thanh toán). Đừng viết tour cho mọi thứ — chúng chậm và giòn hơn.
Hai công dụng, một cơ chế
Điều hay: tour vừa để kiểm thử vừa để hướng dẫn onboarding. Cùng một định nghĩa:
- Khai vào
web.assets_tests→ tour chạy trong test tự động (CI), không hiện cho người dùng. - Khai vào
web.assets_backendvà gắn với một điều kiện → tour chạy cho người dùng thật, hiện bong bóngcontentdẫn họ qua các bước (kiểu "hướng dẫn 5 bước đầu"). Đó là lý do mỗi bước cócontentvàtooltipPosition.
Ba ý mang về
- Tour mô phỏng người dùng đi qua nhiều bước trên UI thật — kiểm thử end-to-end thứ mà unit test không thấy: tích hợp gãy, nút biến mất, luồng đứt giữa chừng. Đăng ký vào
registry.category("web_tour.tours")vớiurl+steps. - Mỗi bước có
trigger(chờ selector xuất hiện) vàrun(hành động: click / "edit chữ" / hàm).triggerlà cách tour tự đồng bộ với UI bất đồng bộ — không cầnsleep. Chạy bằngodoo.startTour(...)hoặcHttpCase.start_tour(...)trong test Python. - Dùng cả unit test lẫn tour, đúng tầng: unit test cho logic (nhanh, nhiều); tour cho vài luồng quan trọng (chậm, ít). Cùng một tour còn dùng lại được làm hướng dẫn onboarding khi khai vào bundle backend.
Ta đã đi hết mảng lập trình web client và kiểm thử. Phần sau chuyển sang mảng website: viết một snippet — khối nội dung kéo–thả mà người dùng tự sắp vào trang bằng trình dựng website của Odoo.