🧵 Automation Testing · Chương 15 · Mục 15.2
Viết test đối chiếu
Trước khi xem code, nắm luồng lô-gíc bài test sẽ làm — 4 bước sau:
- 1.Gọi API
GET /api/roomđể lấy danh sách phòng thật sự có trong hệ thống (dữ liệu gốc, đáng tin). - 2.Mở trang chủ UI, tìm tất cả các thẻ phòng đang hiển thị.
- 3.Với từng thẻ phòng trên UI, lấy ra
roomidcủa nó (giấu trong đường dẫn link "Book now"), rồi tra ngược trong dữ liệu API để lấy đúng tên/giá của phòng đó. - 4.So sánh: tên và giá hiển thị trên UI có khớp với dữ liệu API không.
Tạo file tests/test_05_ket_hop_ui_api.py:
FILE tests/test_05_ket_hop_ui_api.py
"""Demo ket hop UI + API tren Restful-Booker Platform (automationintesting.online).Ky thuat: dung API lam "nguon su that" (ground truth) de kiem tra UI hien thi dung -thay vi dang nhap qua UI de lay session (khong tim duoc mat khau admin cong khai dangtin cay cho trang nay, da ghi lai o docs/test-cases-restful-booker.md)."""import refrom playwright.sync_api import Page, expectdef test_gia_va_ten_phong_tren_trang_chu_khop_voi_api(page: Page, rbp_api_context):"""Goi GET /api/room lay du lieu phong that, roi doi chieu voi tung the phonghien thi tren trang chu - phat hien duoc ngay neu UI hien sai ten/gia phong."""response = rbp_api_context.get("/api/room")assert response.status == 200 # goi API lay du lieu goc thanh congdanh_sach_phong_api = {phong["roomid"]: phong for phong in response.json()["rooms"]} # dict comprehension: tao dict tra cuu nhanh theo roomidpage.goto("https://automationintesting.online/")the_phong = page.locator(".room-card") # tim moi the phong tren trangexpect(the_phong.first).to_be_visible() # cho it nhat 1 the phong hien rafor i in range(the_phong.count()): # duyet qua tung the phong dang hien thithe = the_phong.nth(i) # lay the phong thu ihref = the.get_by_role("link", name="Book now").get_attribute("href") # lay link "Book now" cua the nayroomid = int(re.search(r"/reservation/(\d+)", href).group(1)) # regex tach so id trong duong dan /reservation/{id}assert roomid in danh_sach_phong_api, f"UI hien phong roomid={roomid} nhung API khong co"phong_api = danh_sach_phong_api[roomid] # tra cuu du lieu that cua phong nay qua dictexpect(the.locator(".card-title")).to_have_text(phong_api["type"]) # doi chieu ten loai phongexpect(the.locator(".card-footer")).to_contain_text(f"£{phong_api['roomPrice']}") # doi chieu gia hien thi
Giải thích từng dòng lệnh:
| Dòng | Giải thích |
|---|---|
| def test_...(page: Page, rbp_api_context): | Nhận CẢ 2 fixture — page để thao tác UI, rbp_api_context để gọi API, trong cùng 1 test |
| danh_sach_phong_api = {phong["roomid"]: phong for phong in ...} | Dict comprehension — cách viết gọn tạo dict từ 1 list, ở đây tạo dict tra cứu nhanh theo roomid |
| page.locator(".room-card") | Tìm mọi thẻ phòng trên trang (CSS class .room-card) |
| the_phong.count() | Đếm số phần tử locator tìm được |
| the.get_by_role("link", name="Book now").get_attribute("href") | Lấy giá trị thuộc tính href của link "Book now" trong từng thẻ phòng |
| re.search(r"/reservation/(\d+)", href) | Dùng regex (biểu thức chính quy) tìm số trong đường dẫn dạng /reservation/3?... . r"..." là raw string (không xử lý ký tự đặc biệt). (\d+) nghĩa là "1 nhóm gồm 1 hoặc nhiều chữ số" |
| .group(1) | Lấy đúng phần khớp trong ngoặc () đầu tiên — ở đây là số roomid |
| assert roomid in danh_sach_phong_api | Kiểm tra phòng UI hiện có tồn tại trong dữ liệu API |
| expect(the.locator(".card-title")).to_have_text(...) | Đối chiếu TÊN loại phòng hiển thị đúng với API |
| expect(the.locator(".card-footer")).to_contain_text(...) | Đối chiếu GIÁ hiển thị đúng với API |