CYBERSOFT
Đăng nhập

Mock mạng & WebSocket: routeWebSocket + tracing HAR

Chuyên công nghệFintechPlaywrightMockingAPIThực tế
🗓 1 tháng trước21 phút đọc·👁 1,164 lượt xem👤 62 người đọc

Tất định hóa luồng giá realtime fintech bằng page.route/fulfill, page.routeWebSocket() và browserContext.routeWebSocket(), cùng tracing.startHar()/stopHar() và routeFromHAR — với oracle theo bất biến tiền.

1. Bối cảnh: vì sao mock mạng là kỹ năng bắt buộc của QA fintech

Trong một sàn giao dịch fintech, giá tài sản đến trình duyệt qua hai kênh: REST cho dữ liệu tĩnh (danh mục, số dư) và WebSocket cho luồng giá realtime. Nếu bài kiểm thử của bạn phụ thuộc vào server giá thật, nó sẽ chớp tắt (flaky) mỗi khi thị trường biến động, và bạn gần như không thể tái lập một tình huống hiếm như 'giá rơi 30% trong một giây'. Mục tiêu của mock mạng là biến những đầu vào không kiểm soát được thành đầu vào tất định, để mỗi lần chạy đều cho cùng một kết quả.

Playwright cung cấp ba lớp công cụ cho việc này: page.route/fulfill để chặn và giả lập HTTP, page.routeWebSocket()/browserContext.routeWebSocket() để chặn và sửa WebSocket, và tracing.startHar()/stopHar() để ghi lại toàn bộ lưu lượng thành một tệp HAR rồi phát lại. Bài viết đi xuyên suốt một ví dụ fintech: bảng giá coin realtime, nút Đặt lệnh, và các bất biến nghiệp vụ mà bài kiểm thử phải bảo vệ. Chúng ta sẽ không kiểm 'màn hình hiện thành công' mà kiểm những quy tắc tiền không được vi phạm.

Mock không phải để 'làm test dễ đậu'. Mock là để cô lập hệ thống đang test khỏi thế giới bên ngoài, nhờ đó lỗi tìm được là lỗi của chính hệ thống, không phải nhiễu từ mạng.

2. Nền tảng: page.route và fulfill cho HTTP

Trước khi nói WebSocket, hãy nắm chắc HTTP. page.route đăng ký một trình xử lý cho các request khớp mẫu URL; trong trình xử lý bạn có thể fulfill (trả về phản hồi giả), continue (đi tiếp, có thể sửa header/body), hoặc abort (chặn hẳn). Đây là công cụ để giả lập báo giá REST của một nhà cung cấp bên thứ ba, hoặc cổng thanh toán, mà không cần gọi ra ngoài. Route được đăng ký sau sẽ ưu tiên hơn route đăng ký trước, nên hãy đặt route đặc thù trước route tổng quát.

ts
import { test, expect } from '@playwright/test';

// Giả lập báo giá REST của nhà cung cấp bên thứ ba (deterministic).
test('portfolio hiển thị giá từ quote provider đã mock', async ({ page }) => {
  await page.route('**/api/quotes/BTC', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({ symbol: 'BTC', price: 42000, ts: 1_700_000_000 }),
    });
  });

  await page.goto('/portfolio');
  // Oracle: UI phải render đúng con số ta cấp, không phụ thuộc thị trường thật.
  await expect(page.getByTestId('btc-price')).toHaveText('42,000');
});
💡 Dùng page.route('**/api/**', route => route.abort()) ở đầu suite để 'ngắt mạng' — bất kỳ request nào bạn quên mock sẽ lộ ra ngay, thay vì lẳng lặng gọi ra production.

3. WebSocket là gì và vì sao khó test

WebSocket là kết nối song công (full-duplex) mở lâu dài giữa trình duyệt và server: sau bắt tay HTTP Upgrade, hai bên gửi frame cho nhau bất cứ lúc nào. Đây là xương sống của mọi thứ realtime — bảng giá, sổ lệnh, thông báo. Cái khó khi test là: dữ liệu đến bất đồng bộ và không theo yêu cầu của client, thời điểm frame đến ảnh hưởng trực tiếp tới trạng thái UI, và bạn không thể 'gọi lại' một khoảnh khắc thị trường. Đây chính là nơi routeWebSocket tỏa sáng.

Trình duyệt WebSocket client routeWebSocket() intercept · mock modify frames Price server wss://feed connect connectToServer() Mock hoàn toàn (không nối server) HOẶC nối thật rồi sửa từng frame
Sơ đồ: routeWebSocket đứng giữa client và server — có thể mock hoàn toàn hoặc nối server thật rồi sửa frame.

Có hai chế độ. Chế độ mock hoàn toàn: bạn không nối server thật, tự đóng vai server và bơm chuỗi frame do mình soạn. Chế độ trung gian: bạn gọi ws.connectToServer() để mở kết nối thật, rồi chỉ can thiệp một số frame — ví dụ chèn thêm frame báo 'thị trường tạm dừng', hoặc chặn frame chứa dữ liệu nhạy cảm. Chọn chế độ theo mục tiêu: kiểm logic UI thuần thì mock hoàn toàn; kiểm khả năng chống chịu với dữ liệu bất thường thì dùng trung gian.

4. routeWebSocket: mock hoàn toàn luồng giá coin

Ở chế độ mock hoàn toàn, ta chặn URL WebSocket và tự trả frame. Callback nhận đối tượng WebSocketRoute; ta lắng nghe ws.onMessage() để biết client gửi gì (ví dụ lệnh subscribe), rồi dùng ws.send() để đẩy các bản cập nhật giá theo kịch bản. Vì ta soạn sẵn chuỗi giá, bài test tất định tuyệt đối: cùng đầu vào, cùng thứ tự frame, cùng kết quả UI. Đây là cách kiểm 'khi giá nhảy từ 42,000 lên 42,150 thì P&L của danh mục tăng đúng bao nhiêu'.

ts
import { test, expect } from '@playwright/test';

test('bảng giá cập nhật realtime qua WebSocket đã mock', async ({ page }) => {
  await page.routeWebSocket('wss://feed.exchange.local/stream', (ws) => {
    ws.onMessage((raw) => {
      const msg = JSON.parse(String(raw));
      if (msg.type === 'subscribe' && msg.symbol === 'BTC') {
        // Bơm chuỗi giá tất định — không phụ thuộc thị trường thật.
        ws.send(JSON.stringify({ type: 'tick', symbol: 'BTC', price: 42000 }));
        ws.send(JSON.stringify({ type: 'tick', symbol: 'BTC', price: 42150 }));
      }
    });
  });

  await page.goto('/trade/BTC');
  await expect(page.getByTestId('last-price')).toHaveText('42,150');
  // Oracle: P&L = (giá mới - giá vào) * số lượng. Không kiểm 'màn hình xanh'.
  await expect(page.getByTestId('pnl')).toHaveText('+150.00');
});
🔒

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!