1. Bối cảnh: một đơn hàng TMĐT phải đi qua bao nhiêu hệ thống
Một sàn TMĐT quy mô lớn không phải là một website đơn lẻ mà là một tập hợp dịch vụ: catalog, giỏ hàng, khuyến mãi, thanh toán, kho, vận chuyển và thông báo. Khi khách bấm 'Đặt hàng', luồng đi qua ít nhất năm biên giới dịch vụ, mỗi biên là một điểm có thể hỏng. Nhóm QA của chúng ta phục vụ SLA 99.9% cho luồng checkout, đỉnh tải 12.000 đơn mỗi phút trong ngày sale, và chịu ràng buộc tuân thủ PCI-DSS ở lớp thanh toán. Vì thế một bài kiểm thử E2E thuần UI là chưa đủ; ta cần tích hợp UI, API, CI và cả tác nhân AI để phủ được cả bề rộng lẫn bề sâu.
Bài viết này ghép bốn mảnh thành một dây chuyền duy nhất. Playwright lo phần trải nghiệm người dùng thật trên trình duyệt; API request context của Playwright lo phần dựng dữ liệu và làm oracle (nguồn chân lý) để không phải phụ thuộc vào UI khi kiểm tra kết quả; GitHub Actions lo việc chạy song song bằng shard rồi gộp báo cáo blob; và bộ Playwright Agents (Planner, Generator, Healer) lo việc sinh và tự chữa kiểm thử dưới một cổng review của con người. Mục tiêu cuối là một pipeline mà mỗi lần merge đều xác nhận bất biến nghiệp vụ của luồng đặt hàng.
2. Kiến trúc dây chuyền và mô hình dữ liệu
Trước khi viết dòng code nào, ta cần một bức tranh chung để cả nhóm nói cùng ngôn ngữ. Kiến trúc kiểm thử phản chiếu kiến trúc sản phẩm: một lớp UI (Playwright browser), một lớp API (request context tới các microservice), một lớp điều phối (GitHub Actions), và một lớp trí tuệ (AI agents). Dữ liệu chảy theo một chiều: agent sinh test, CI chạy test song song, mỗi test dựng seed qua API, thao tác UI, rồi phán xử bằng API và trace.
Mô hình dữ liệu tối thiểu để kiểm thử luồng đặt hàng gồm: Product (id, giá, tồn kho), Cart (dòng hàng), Order (trạng thái, tổng tiền, khoá idempotency) và Payment (số tiền, trạng thái giao dịch). Bất biến nghiệp vụ mà chúng ta bảo vệ chính là những ràng buộc giữa các thực thể này: tồn kho không bao giờ âm, tổng tiền đơn bằng tổng dòng cộng phí trừ khuyến mãi, và một khoá idempotency chỉ tạo đúng một đơn dù người dùng bấm hai lần.
3. Bất biến làm oracle: đừng khẳng định 'thấy thành công'
Sai lầm phổ biến của E2E là kiểm tra rằng màn hình hiển thị chữ 'Đặt hàng thành công'. Câu đó dễ đỏ đèn xanh giả: UI có thể hiện thông báo trong khi kho chưa trừ, tiền chưa trừ, hay đơn bị nhân đôi. Oracle đúng phải là bất biến nghiệp vụ, và cách kiểm bất biến chính xác nhất là hỏi API chứ không phải đọc DOM. Với mỗi đơn, ta kiểm bốn bất biến: tồn kho giảm đúng số lượng đã mua, không âm; tiền được ghi sổ kép cân bằng; đơn ở trạng thái hợp lệ theo bảng quyết định; và idempotency đảm bảo retry không sinh đơn thứ hai.
// oracle.ts — kiểm bất biến nghiệp vụ qua API request context
import { APIRequestContext, expect } from '@playwright/test';
export async function assertOrderInvariants(
api: APIRequestContext,
orderId: string,
expected: { productId: string; qty: number; stockBefore: number }
) {
const order = await (await api.get(`/api/orders/${orderId}`)).json();
const inv = await (await api.get(`/api/inventory/${expected.productId}`)).json();
// 1) tồn kho không âm và giảm đúng
expect(inv.available).toBeGreaterThanOrEqual(0);
expect(inv.available).toBe(expected.stockBefore - expected.qty);
// 2) sổ kép cân bằng: debit == credit
const ledger = await (await api.get(`/api/orders/${orderId}/ledger`)).json();
const debit = ledger.entries.filter((e:any)=>e.side==='debit').reduce((s:any,e:any)=>s+e.amount,0);
const credit = ledger.entries.filter((e:any)=>e.side==='credit').reduce((s:any,e:any)=>s+e.amount,0);
expect(debit).toBe(credit);
// 3) trạng thái đơn nằm trong tập hợp lệ
expect(['PAID','CONFIRMED']).toContain(order.status);
}❓ Tại sao không nên tin assertion 'màn hình hiện Đặt hàng thành công'?
Vì đó là một oracle yếu: thông báo trên UI chỉ phản ánh trạng thái phía client, không phản ánh trạng thái đã cam kết ở backend. Trong hệ phân tán, UI có thể lạc quan hiển thị thành công trong khi service kho hoặc thanh toán mới ở trạng thái pending, đã rollback, hay bị nhân đôi. Oracle mạnh phải kiểm bất biến ở nguồn dữ liệu thật qua API: kho không âm, sổ kép cân, đúng một đơn. Assertion text chỉ nên là kiểm phụ về UX, không bao giờ là bằng chứng nghiệp vụ.
4. API request context: dựng seed và làm nguồn chân lý
Playwright cung cấp một request context chạy độc lập với trình duyệt, dùng cùng cơ chế lưu trữ và proxy. Ta dùng nó cho hai việc: dựng dữ liệu ban đầu (tạo sản phẩm, nạp tồn kho, tạo tài khoản test) và xác minh kết quả sau khi thao tác UI. Việc dựng qua API nhanh hơn nhiều lần so với bấm qua UI, và quan trọng hơn, nó làm test trở nên xác định. Nếu bạn tạo dữ liệu bằng UI, một lỗi ở form đăng ký cũng làm hỏng test checkout — đó là ghép cặp sai.
💬 Bình luận (0)
Chưa có bình luận nào. Hãy là người đầu tiên!