Offline Mode & Color Scheme (Giả lập mất mạng, dark mode và media features)
automationplaywright
Playwright cho phép bật chế độ offline (context.setOffline) và giả lập media features (colorScheme dark/light, reducedMotion, forcedColors, media print) ở context/page — đủ để test PWA offline UX và dark mode mà không cần đổi OS theme hay rút dây mạng.
Khái niệm & Bản chất
offline= cắt network ở context:context.setOffline(true)khiến mọi request trong context fail như mất mạng — nhưng service worker vẫn hoạt động → đúng điều kiện test PWA cache/fallback.colorSchemeemulateprefers-color-scheme: giá trị'dark' | 'light' | 'no-preference' | null— trang nhận qua media query vàmatchMedia('(prefers-color-scheme: dark)').- Media features khác cùng API:
media: 'print' | 'screen'(CSS @media print),reducedMotion: 'reduce'(prefers-reduced-motion),forcedColors,contrast— tất cả quapage.emulateMedia()hoặc context options. - Khác network throttling:
setOfflinechỉ ON/OFF — Playwright không có built-in 'slow 3G'; muốn throttle phải qua CDP session hoặc proxy ngoài.
Cách hoạt động & API chính
- Context options:
browser.newContext({ offline: true, colorScheme: 'dark' })— áp dụng ngay từ đầu cho mọi page trong context. context.setOffline(offline: boolean): bật/tắt mạng runtime — pattern kinh điển: load trang online trước, setOffline(true), reload → kiểm PWA hiển thị gì.page.emulateMedia({ colorScheme, media, reducedMotion, ... }): đổi media runtime trên 1 page; truyềnnullđể reset về system.- Config per-project:
use: { colorScheme: 'dark' }trongprojects→ chạy lại suite dưới dark mode chỉ bằng 1 flag. page.routevẫn hoạt động khi offline: route handler chạy trước tầng network — có thể 'offline nhưng API X vẫn trả data mock'.
Ví dụ & Cú pháp thực tế
- Dark mode test:
``
ts const context = await browser.newContext({ colorScheme: 'dark' }); const page = await context.newPage(); // hoặc đổi runtime trên page có sẵn await page.emulateMedia({ colorScheme: 'dark' }); await page.goto('/'); await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(18, 18, 18)');`` - PWA offline flow — pattern chuẩn:
``
ts test('app vẫn dùng được khi mất mạng', async ({ page, context }) => { await page.goto('/'); await page.waitForLoadState('networkidle'); // đợi SW cache xong await context.setOffline(true); await page.reload(); await expect(page.getByText('Bạn đang offline')).toBeVisible(); await expect(page.getByRole('button', { name: 'Xem dữ liệu đã lưu' })).toBeVisible(); });`` - Print stylesheet + PDF:
``
ts await page.emulateMedia({ media: 'print' }); await page.goto('/invoice/123'); await page.pdf({ path: 'invoice.pdf', format: 'A4' });`` - Giảm animation cho test ổn định:
``
ts test.use({ reducedMotion: 'reduce' }); // tắt animation prefers-reduced-motion``
Best practices & Khi nào dùng
- Offline: luôn load online trước: service worker cần 1 lần chạy để cache —
goto→networkidle→setOffline(true)→reloadlà thứ tự chuẩn. - Dark mode: test cả CSS lẫn screenshot:
toHaveCSScheck giá trị token, nhưng dark mode hay vỡ ở ảnh/icon ngược sáng — kết hợptoHaveScreenshot. reducedMotion: 'reduce'chống flake: app tôn trọng setting này sẽ skip animation → element ổn định ngay, ít chờ đợi.- Muốn 'API X chết' thì đừng offline cả trang: dùng
page.route('**/api/x', r => r.abort())— offline toàn cục kéo chết cả asset. - Tách project riêng cho dark mode:
{ name: 'dark', use: { colorScheme: 'dark' } }— không nhét if/else dark vào từng test.
Gotchas, So sánh & Lưu ý
colorSchemechỉ ảnh hưởng media query: nếu site toggle dark bằng nút bấm +localStorage/data-theme, emulation không đổi gì — phảiaddInitScriptset localStorage hoặc click toggle thật.- Offline ≠ flaky network:
setOfflinelà cắt hẳn — không giả lập được mất gói tin, latency cao, mạng chập chờn; cần thế thì CDPNetwork.emulateNetworkConditions. page.emulateMediaper-page, context option per-context: page mới trong context KHÔNG inherit emulateMedia của page cũ — set ở context nếu muốn global.- Request sang test server cũng bị chặn: nếu API server khác origin và bạn setOffline, mọi request đều fail — trừ request đã
page.routefulfill. media: 'print'thay đổi layout hoàn toàn: nhiều trang ẩn hết nav/ad khi print — hữu ích cho test PDF nhưng đừng quên reset về'screen'/null.
