Wiki

← Tất cả bài wiki

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.
  • colorScheme emulate prefers-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ả qua page.emulateMedia() hoặc context options.
  • Khác network throttling: setOffline chỉ 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ền null để reset về system.
  • Config per-project: use: { colorScheme: 'dark' } trong projects → chạy lại suite dưới dark mode chỉ bằng 1 flag.
  • page.route vẫ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) → reload là thứ tự chuẩn.
  • Dark mode: test cả CSS lẫn screenshot: toHaveCSS check giá trị token, nhưng dark mode hay vỡ ở ảnh/icon ngược sáng — kết hợp toHaveScreenshot.
  • 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 ý

  • colorScheme chỉ ả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ải addInitScript set localStorage hoặc click toggle thật.
  • Offline ≠ flaky network: setOffline là 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ì CDP Network.emulateNetworkConditions.
  • page.emulateMedia per-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.route fulfill.
  • 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.