Wiki

← Tất cả bài wiki

Geolocation, Permissions & Locale/Timezone (Giả lập vị trí, quyền trình duyệt, ngôn ngữ, múi giờ)

automationplaywright

Browser context options cho phép giả lập tọa độ GPS, cấp/từ chối quyền trình duyệt (geolocation, camera, notifications...) và set locale + timezone cho trang — tất cả deterministic trong test. Đây là cách duy nhất test các flow 'browser hỏi quyền' hay UI phụ thuộc vị trí/ngôn ngữ mà không cần rời máy dev.

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

  • Ba nhóm môi trường context-level: geolocation (lat/long/accuracy giả), permissions (danh sách quyền đã grant), và cặp locale + timezoneId (ngôn ngữ & múi giờ của trang).
  • Permission popup không click được: popup 'Allow location?' là native UI của browser, ngoài DOM — cách duy nhất là grant/deny qua context trước khi trang gọi navigator.geolocation.
  • locale ảnh hưởng: navigator.language, header Accept-Language, và định dạng Intl (ngày/số). timezoneId ảnh hưởng: new Date(), Intl.DateTimeFormat().resolvedOptions().timeZone trong trang.
  • Geolocation gắn với permission: set tọa độ mà không grant quyền → trang vẫn 'prompt' và getCurrentPosition lỗi — hai option phải đi cùng nhau.

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

  • Khai báo lúc tạo context: browser.newContext({ geolocation: { latitude, longitude, accuracy }, permissions: ['geolocation'], locale: 'vi-VN', timezoneId: 'Asia/Ho_Chi_Minh' }).
  • context.grantPermissions(permissions, { origin? }): grant runtime; truyền origin để giới hạn quyền chỉ cho 1 domain — hữu ích khi trang embed iframe domain khác.
  • context.setGeolocation({ latitude, longitude }): đổi tọa độ giữa chừng — trang đang watchPosition sẽ nhận event vị trí mới, giả lập 'người dùng di chuyển'.
  • context.clearPermissions(): thu hồi toàn bộ quyền đã grant — dùng test kịch bản 'user revoke quyền'.
  • Danh sách permission theo Chromium: 'geolocation', 'notifications', 'camera', 'microphone', 'clipboard-read', 'clipboard-write', 'midi', 'accelerometer'... (Firefox/WebKit hỗ trợ ít hơn).
  • timezoneId theo chuẩn IANA: 'Asia/Ho_Chi_Minh', 'America/New_York' — sai tên → throw lúc newContext.

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

  • Persona 'user ở TP.HCM, tiếng Việt': ``ts const context = await browser.newContext({ geolocation: { latitude: 10.762622, longitude: 106.660172, accuracy: 100 }, permissions: ['geolocation'], locale: 'vi-VN', timezoneId: 'Asia/Ho_Chi_Minh', }); ``
  • Test trang đổi theo vị trí: ``ts test('hiển thị cửa hàng gần nhất theo GPS', async ({ page, context }) => { // đổi vị trí sang Hà Nội giữa chừng await context.setGeolocation({ latitude: 21.028511, longitude: 105.804817 }); await page.goto('/stores'); await expect(page.getByText('Cửa hàng Hà Nội')).toBeVisible(); }); ``
  • Kịch bản user TỪ CHỐI quyền: không grant — navigator.permissions.query trả 'prompt'/'denied': ``ts const denied = await browser.newContext({ permissions: [] }); const page = await denied.newPage(); await page.goto('/check-in'); await expect(page.getByText('Vui lòng bật định vị')).toBeVisible(); ``
  • Locale/timezone cho cả file spec: ``ts test.use({ locale: 'ja-JP', timezoneId: 'Asia/Tokyo' }); test('định dạng ngày kiểu Nhật', async ({ page }) => { await page.goto('/orders'); await expect(page.getByText('2025/01/15')).toBeVisible(); }); ``

Best practices & Khi nào dùng

  • Dùng khi: trang có 'tìm cửa hàng gần nhất', map check-in, nội dung đa ngôn ngữ (i18n), giá/ngày định dạng theo locale, countdown theo múi giờ user, feature cần camera/clipboard.
  • Grant ở context chứ không phải patch từng page: permission là state của context — giữ test độc lập, không rò giữa test.
  • Test cả 3 nhánh quyền: granted → feature chạy; denied/prompt → fallback UI; revoke giữa chừng (clearPermissions) → trang xử lý thế nào.
  • Test i18n cặp locale+timezone: đổi locale KHÔNG tự đổi timezone — app render 'tomorrow' sai nếu chỉ đổi 1 trong 2.
  • Origin-scoped permission: grantPermissions([...], { origin: 'https://app.com' }) khi trang nhúng iframe/payment domain khác.

Gotchas, So sánh & Lưu ý

  • Set geolocation nhưng quên grant permission là lỗi #1: tọa độ có sẵn nhưng trang vẫn bị chặn quyền → getCurrentPosition reject.
  • Danh sách quyền lệch giữa browser: 'clipboard-write' Chrome OK; Firefox/WebKit hỗ trợ ít quyền hơn — check trên từng engine khi test cross-browser.
  • timezoneId chỉ ảnh hưởng TRONG trang: new Date() ở code Node của test file vẫn chạy giờ máy local — đừng lẫn khi so sánh timestamp server-side.
  • Không phải 'máy bay mode': geolocation giả vẫn trả toạ độ thành công tức thì — không giả lập được 'GPS yếu, fix chậm, timeout' (muốn thế phải mock navigator.geolocation bằng addInitScript).
  • Khác với Clock API: timezoneId đổi múi giờ hiển thị, page.clock điều khiển trôi thời gian — hai thứ độc lập, hay dùng chung khi test lịch/deadline.