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.innerWidththeo DPR. - Registry
devicescó sẵn: Playwright bundle một objectdevices(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
devicestừ@playwright/test: mỗi preset là object{ viewport, userAgent, deviceScaleFactor, isMobile, hasTouch, defaultBrowserType }— spread thẳng vàousehoặcnewContext().- Khai báo ở
playwright.config.tsquaprojects: mỗi project = 1 device → cùng 1 spec chạy trên nhiều 'máy' chỉ bằngnpx 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
hasTouchcho 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,colorSchemetrong 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;setViewportSizechỉ đổi 1 chiều kích thước, không đổi UA/touch.
