第 12 章 · 设备仿真与多浏览器
本章目标:学会用内置设备字典模拟手机/平板,配置地理位置、语言、时区、深色模式等环境特征,并把测试矩阵扩展到 Chromium、Firefox、WebKit 三大内核。
12.1 设备描述符:devices 字典
Playwright 内置了常见设备的参数注册表(user agent、屏幕尺寸、viewport、是否触屏等),一行代码即可"变成"一台 iPhone:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
iphone = p.devices["iPhone 13"] # 取出该设备的完整参数字典
browser = p.webkit.launch() # 移动端设备建议配 WebKit(iOS 内核)
context = browser.new_context(**iphone, locale="zh-CN")
page = context.new_page()
page.goto("https://m.example.com")设备与内核的搭配
官方示例中 iPhone 系列用 WebKit 打开——因为真机 iOS Safari 的内核就是 WebKit,这样仿真保真度最高;Android 设备(Pixel 等)则应搭配 Chromium。用错内核不会报错,但会损失仿真真实性。
注意一个细节:预置的桌面设备参数(如 "Desktop Chrome")带的是 Windows 平台的 UA。若想用本机平台的真实 UA,可以显式覆盖为 None:
desktop = p.devices["Desktop Chrome"]
context = browser.new_context(**desktop, user_agent=None)12.2 手工定制仿真参数
不套用预设时,context 参数可以直接指定。这些参数在 context 创建时固定,其中 viewport 还能按页动态调整:
context = browser.new_context(
viewport={"width": 1280, "height": 720}, # 视口尺寸
is_mobile=True, # 移动端标志(影响 meta viewport 处理)
has_touch=True, # 启用触屏事件
device_scale_factor=2, # 高 DPI 屏,影响截图清晰度
)
# 单页调整视口(响应式断点测试)
page.set_viewport_size({"width": 375, "height": 812})
expect(page.get_by_test_id("mobile-menu")).to_be_visible()is_mobile 与 has_touch 的区别值得强调:前者让页面把自身当作移动设备渲染(响应式布局生效),后者只决定触控事件是否可用——模拟 iPad 竖屏浏览通常两个都要开。
12.3 环境 Locale、时区与权限
国际化与本地化行为是手工测试最容易遗漏的部分,Playwright 可以精确仿真:
context = browser.new_context(
locale="de-DE", # 界面语言/格式化区域
timezone_id="Europe/Berlin", # IANA 时区
geolocation={"latitude": 52.52, "longitude": 13.405},
permissions=["geolocation"], # 预授权,避免权限弹窗
)
page.goto("https://example.com")
page.evaluate("navigator.language") # -> 'de-DE'常用权限还包括 "notifications"、"camera"、"microphone"。反过来要测试"用户拒绝定位"的场景,可以先授予权限再用 context.clear_permissions() 撤销。
12.4 深色模式与 UA 伪装
深色模式适配 bug 是高频线上问题,color_scheme 一键切换:
dark = browser.new_context(color_scheme="dark")
page = dark.new_page()
page.emulate_media(color_scheme="dark") # 单页级别随时切换
body_bg = page.evaluate(
"getComputedStyle(document.body).backgroundColor"
)
print(body_bg) # 断言不是纯白即适配了暗色UA 伪装用于验证"站点对旧浏览器降级"等逻辑:
context = browser.new_context(user_agent="Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)")
page.goto("https://example.com")
assert page.get_by_text("请升级浏览器").is_visible()UA 只是字符串
改 UA 并不会改变引擎能力——CSS/JS 特性支持仍由真实内核决定。需要测引擎差异时,老老实实跑多内核矩阵,别指望伪装。
12.5 三内核矩阵测试
pytest-playwright 用 --browser 参数即可把同一批用例铺到多个内核上执行:
pip install pytest-playwright playwright
playwright install chromium firefox webkit # 安装三个内核
pytest --browser chromium # 只跑 Chromium
pytest --browser chromium --browser firefox --browser webkit # 三内核全跑
pytest --browser-channel chrome # 甚至可以用系统安装的 Chrome工程化建议:日常提交只跑 Chromium 保证速度,合并前/夜间任务再跑全矩阵;对已知内核差异(如 WebKit 对某些 CSS 特性的滞后支持)用 @pytest.mark.skip_browser("webkit") 显式标注原因,而不是全局回避。
本章小结
p.devices["iPhone 13"]提供完整设备参数,new_context(**device)应用;移动端配 WebKit、Android 配 Chromium;is_mobile管渲染模式、has_touch管触控事件,两者独立;locale / timezone_id / geolocation / permissions覆盖国际化与权限场景,clear_permissions()可撤销;color_scheme="dark"+emulate_media测试深色模式;UA 伪装不改引擎能力;- 多内核矩阵交给
--browser参数重复传入即可。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 用 Playwright 模拟 iOS 设备上的 Safari,推荐的内核组合是?
2. context 参数中 is_mobile 和 has_touch 的关系是?
3. 修改 user_agent 字符串能做到什么、不能做到什么?
4. 想让一批用例在 Chromium、Firefox、WebKit 上都跑一遍,最简单的做法是?
🛠️ 动手实践
- 用 iPhone 13 + WebKit 访问任一响应式站点,分别在 375px 与 768px 视口下断言导航栏形态切换。
- 构造
locale="ja-JP"的 context,验证日期显示格式随区域变化(或断言Intl.DateTimeFormat().resolvedOptions().locale)。 - 编写深色模式测试:切到 dark 后断言 body 背景色亮度低于浅色模式下的取值。