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ặplocale+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, headerAccept-Language, và định dạngIntl(ngày/số).timezoneIdảnh hưởng:new Date(),Intl.DateTimeFormat().resolvedOptions().timeZonetrong trang.- Geolocation gắn với permission: set tọa độ mà không grant quyền → trang vẫn 'prompt' và
getCurrentPositionlỗ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ềnoriginđể 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 đangwatchPositionsẽ 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). timezoneIdtheo chuẩn IANA:'Asia/Ho_Chi_Minh','America/New_York'— sai tên → throw lúcnewContext.
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.querytrả'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
localeKHÔ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 →
getCurrentPositionreject. - 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. timezoneIdchỉ ả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.geolocationbằngaddInitScript). - 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.
