1. Bối cảnh: một pipeline E2E cho luồng đặt hàng
Ở một sàn TMĐT thật, luồng đặt hàng (order flow) đi qua nhiều dịch vụ: giỏ hàng, tồn kho, coupon/thuế, thanh toán, tạo đơn. Kiểm thử E2E qua UI dễ giòn và chậm; kiểm thử API nhanh nhưng bỏ lỡ tích hợp UI thật. Bài này dựng MỘT pipeline tích hợp: Playwright điều khiển UI như người dùng, đồng thời dùng request-context của Playwright gọi thẳng API để làm oracle. Mục tiêu là mỗi lần merge vào main, pipeline khẳng định lại các bất biến order-flow — không phải chỉ 'thấy nút Đặt hàng bấm được'.
Pipeline tích hợp thêm hai mảnh hiện đại. Thứ nhất: GitHub Actions chạy test theo shard (chia nhỏ) song song rồi gộp báo cáo blob thành một report duy nhất — để bộ E2E lớn vẫn nhanh. Thứ hai: bộ Playwright Agents (Planner / Generator / Healer, từ v1.56+) hỗ trợ CON NGƯỜI: Planner khám phá app viết kế hoạch Markdown, Generator biến kế hoạch thành spec chạy được và tự kiểm locator trên app sống, Healer chạy trong debug soi console/network/snapshot để vá test đỏ. Mọi thứ agent tạo đều qua cổng review người trước khi vào main.
- Playwright điều khiển UI thật; request-context API là oracle nghiệp vụ.
- GitHub Actions: sharding song song + gộp blob report thành một.
- Playwright Agents (Planner/Generator/Healer) hỗ trợ, người review.
- Mỗi merge = một lần khẳng định lại bất biến order-flow.
2. Bất biến order-flow làm oracle
Trước khi viết test, ta chốt các bất biến — thứ luôn đúng dù người dùng bấm gì. Chúng là oracle: test 'pass' nghĩa là bất biến giữ nguyên, không phải 'màn hình hiện chữ thành công'. Với order-flow: tồn kho không âm và không oversell; tổng tiền = Σ(giá×số lượng) − giảm giá + thuế + phí ship, khớp giữa UI và API; coupon áp đúng quy tắc (không âm, không quá trần); thanh toán idempotent (retry không tạo hai đơn/hai lần trừ tiền); trạng thái đơn cuối là một giá trị hợp lệ duy nhất.
// oracle/order-invariants.ts — bất biến dùng chung cho UI test và API test
export interface OrderView { subtotal: number; discount: number; tax: number; shipping: number; total: number; }
export function assertMoneyInvariant(o: OrderView) {
const expected = o.subtotal - o.discount + o.tax + o.shipping;
if (Math.round(o.total) !== Math.round(expected))
throw new Error(`total sai: ${o.total} ≠ ${expected}`);
if (o.discount < 0) throw new Error("discount âm");
}
export function assertCouponCap(discount: number, cap: number) {
if (discount < 0 || discount > cap) throw new Error(`discount ${discount} vượt trần ${cap}`);
}3. Kiến trúc pipeline: UI + API + CI + agent
Toàn cảnh pipeline gồm bốn lớp. Lớp UI: các spec Playwright thao tác trình duyệt như người dùng. Lớp Oracle-API: request-context gọi API để dựng dữ liệu (arrange), đọc trạng thái thật (assert) và dọn dẹp — nhanh và ổn định hơn đọc DOM. Lớp CI: GitHub Actions chia shard, chạy song song, gộp blob report. Lớp Agent: Planner/Generator/Healer hỗ trợ soạn và bảo trì test, luôn dưới review người. Bốn lớp cùng một mục tiêu: mỗi merge khẳng định lại bất biến.
// playwright.config.ts — cấu hình cho pipeline tích hợp (Chrome for Testing, trace)
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./tests",
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? [["blob"]] : [["html"]], // CI xuất blob để gộp
use: {
baseURL: process.env.BASE_URL ?? "http://localhost:3000",
trace: "retain-on-failure-and-retries", // trace khi fail/retry
video: "on-first-retry",
},
projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
});
💬 Bình luận (0)
Chưa có bình luận nào. Hãy là người đầu tiên!