Wiki

← Tất cả bài wiki

Device Emulation (Giả lập thiết bị: viewport, userAgent, devices preset)

automationplaywright

Device emulation là khả năng giả lập toàn bộ môi trường thiết bị (viewport, userAgent, deviceScaleFactor, isMobile, hasTouch) ở tầng browser context — trang web 'nhìn thấy' mình đang chạy trên iPhone 13 hay Pixel 7 thật. Playwright ship sẵn registry devices với hàng trăm preset đồng bộ theo Chrome DevTools. Giá trị lớn nhất: test responsive và hành vi mobile mà không cần device farm hay emulator thật.

Khái niệm & Bản chất

  • Device emulation = giả lập fingerprint thiết bị ở tầng BrowserContext: gồm viewport (kích thước khung nhìn), userAgent (chuỗi nhận diện trình duyệt/thiết bị), deviceScaleFactor (DPR — mật độ pixel), isMobile (bật meta viewport + mobile emulation), hasTouch (touch events) — tất cả đều là context options, không phải máy ảo.
  • Khác với 'resize window' đơn thuần: đổi viewport chỉ co giãn khung nhìn; emulation đổi cả cách trang nhận diện thiết bị — media query pointer:coarse, navigator.userAgent, touch event support, window.innerWidth theo DPR.
  • Registry devices có sẵn: Playwright bundle một object devices (lấy từ DevTools device list) với preset kiểu 'iPhone 13', 'Pixel 7', 'iPad Mini', 'Desktop Chrome HiDPI' — import trực tiếp, không phải tự gõ userAgent.
  • Emulation per-context → test matrix song song: mỗi browser.newContext() là 1 'thiết bị' độc lập — chạy đồng thời session mobile + desktop trong cùng 1 browser process.

Cách hoạt động & API chính

  • devices từ @playwright/test: mỗi preset là object { viewport, userAgent, deviceScaleFactor, isMobile, hasTouch, defaultBrowserType } — spread thẳng vào use hoặc newContext().
  • Khai báo ở playwright.config.ts qua projects: mỗi project = 1 device → cùng 1 spec chạy trên nhiều 'máy' chỉ bằng npx playwright test.
  • Override lên preset: { ...devices['iPhone 13'], locale: 'vi-VN' } — preset chỉ là object nên nối thêm option tuỳ ý.
  • page.setViewportSize({ width, height }): đổi viewport runtime giữa test (ví dụ test breakpoint responsive), không cần context mới.
  • Giới hạn isMobile: chỉ Chromium và WebKit hỗ trợ — preset mobile gán cho project Firefox sẽ throw error ngay lúc tạo context.

Ví dụ & Cú pháp thực tế

  • Device matrix trong config — chạy cùng test trên 3 'máy': ``ts // playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ projects: [ { name: 'desktop', use: { ...devices['Desktop Chrome'] } }, { name: 'iphone', use: { ...devices['iPhone 13'] } }, { name: 'android', use: { ...devices['Pixel 7'] } }, ], }); // chạy 1 project riêng: npx playwright test --project=iphone ``
  • newContext với preset + override: ``ts const context = await browser.newContext({ ...devices['iPhone 13'], locale: 'vi-VN', // thêm ngôn ngữ geolocation: { latitude: 10.76, longitude: 106.66 }, permissions: ['geolocation'], }); const page = await context.newPage(); ``
  • Đổi viewport giữa test để kiểm breakpoint: ``ts test('menu mobile collapse', async ({ page }) => { await page.goto('/'); await page.setViewportSize({ width: 375, height: 812 }); // hamburger chỉ hiện dưới 768px await expect(page.getByRole('button', { name: 'Menu' })).toBeVisible(); }); ``
  • Override cho cả file spec bằng test.use: ``ts test.use({ ...devices['iPad Mini'], viewport: { width: 768, height: 1024 } }); test('tap trên màn hình cảm ứng', async ({ page }) => { await page.goto('/gallery'); await page.touchscreen.tap(200, 300); // cần hasTouch: true }); ``

Best practices & Khi nào dùng

  • Chọn project theo thiết bị user THẬT: lấy top device từ analytics rồi map sang preset gần nhất — đừng bắn 30 preset cho có, mỗi project nhân bộ test lên.
  • Test hành vi, không test pixel: emulation dùng để kiểm 'menu có collapse không', 'nút có chạm được không' — pixel-perfect để cho visual testing lo.
  • Tận dụng hasTouch cho touch-only flow: page.touchscreen.tap(), swipe, tap-highlight — những thứ desktop không có.
  • Ghim device cố định cho snapshot/visual test: đổi DPR hay viewport là ảnh screenshot khác ngay → flake so ảnh.
  • Kết hợp với locale, geolocation, colorScheme trong cùng context option để dựng 'persona môi trường' hoàn chỉnh.

Gotchas, So sánh & Lưu ý

  • Emulation ≠ thiết bị thật: không giả lập CPU/GPU yếu, cảm biến, notch, hay Safari toolbar co giãn trên iOS — flow thanh toán/nghiệp vụ quan trọng vẫn nên sanity trên máy thật hoặc BrowserStack.
  • userAgent đổi nhưng engine render không đổi: preset 'iPhone 13' trên project chromium vẫn render bằng Chromium — không phải Safari/WebKit thật; muốn WebKit thật phải chạy project webkit.
  • Firefox không hỗ trợ isMobile: tách project mobile chỉ cho chromium/webkit, để firefox chạy desktop preset.
  • deviceScaleFactor ảnh hưởng kích thước screenshot: DPR=3 → ảnh gấp 3 lần pixel — nhớ khi so sánh ảnh hay crop element shot.
  • Headless không có 'window chrome': viewport size chính là page size — khác browser có giao diện thật nơi viewport < window size.
  • So với page.emulateMedia/setViewportSize: emulation device là combo 'full gói' khai báo lúc tạo context; setViewportSize chỉ đổi 1 chiều kích thước, không đổi UA/touch.