最近在MacOS环境下使用Playwright进行Web自动化测试时,遇到了一个颇为棘手的问题:明明在配置文件中指定了使用Chromium浏览器,但每次启动测试脚本时,系统却总是自动调用Safari浏览器执行测试用例。这个问题直接影响了我们的持续集成流程,因为测试环境并未安装Safari的WebDriver,导致每次运行都会报错。
具体现象表现为:
setting.json配置文件中已明确设置"browser": "chromium"提示:这个问题在Playwright社区中并不常见,官方文档也没有明确说明这种特殊情况,因此排查过程颇费周折。
首先检查了项目中的两个关键配置文件:
json复制{
"browser": "chromium",
"headless": false,
"viewport": {
"width": 1920,
"height": 1080
}
}
json复制{
"env": "test",
"base_url": "http://localhost:8080",
"timeout": 30000
}
从配置上看,浏览器类型明确指定为Chromium,理论上不应该出现调用Safari的情况。于是开始怀疑是否是代码中有硬编码覆盖了配置。
对测试启动代码进行了详细检查,特别是浏览器初始化的部分:
python复制import playwright
from playwright.sync_api import sync_playwright
def launch_browser():
with sync_playwright() as p:
# 理论上应该从配置读取浏览器类型
browser = p.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
# ...后续测试逻辑
即使强制指定使用chromium,运行时仍然调用了Safari。这让我们意识到问题可能不在代码层面。
通过以下命令检查系统默认浏览器设置:
bash复制defaults read com.apple.Safari DefaultBrowser
输出显示:
code复制Safari
进一步检查Playwright的浏览器发现逻辑:
python复制from playwright.__main__ import install
print(install.installed_browsers())
输出确认已正确安装Chromium:
code复制['chromium', 'firefox', 'webkit']
经过多次测试验证,发现问题根源在于:
MacOS系统的默认浏览器设置会覆盖Playwright的配置。当系统默认浏览器为Safari时,即使代码和配置明确指定使用Chromium,Playwright在某些情况下仍会优先尝试使用系统默认浏览器。
这种设计可能是为了:
根据实际测试,我们总结了三种可行的解决方案:
| 方案 | 操作步骤 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 修改系统默认浏览器 | 系统设置 > 通用 > 默认浏览器 > 改为Chrome | 一劳永逸 | 影响其他应用 | 个人开发环境 |
| 显式指定浏览器参数 | playwright launch --browser=chromium |
精准控制 | 需修改启动脚本 | CI/CD环境 |
| 代码强制指定 | browser = p.chromium.launch() |
代码可控 | 需修改多处代码 | 大型测试项目 |
对于大多数项目,我们推荐代码强制指定+环境变量覆盖的组合方案:
python复制def launch_browser():
with sync_playwright() as p:
# 从环境变量读取浏览器类型,默认chromium
browser_type = os.getenv('PLAYWRIGHT_BROWSER', 'chromium')
browser = getattr(p, browser_type).launch(
headless=os.getenv('PLAYWRIGHT_HEADLESS', 'false').lower() == 'true'
)
# ...后续逻辑
yaml复制env:
PLAYWRIGHT_BROWSER: "chromium"
PLAYWRIGHT_HEADLESS: "true"
.env文件覆盖:code复制PLAYWRIGHT_BROWSER=firefox
PLAYWRIGHT_HEADLESS=false
Playwright的浏览器选择遵循以下优先级:
--browser选项browser设置在MacOS环境下,当上述1-3项未明确指定或指定无效时,会意外触发第4级选择策略。
JSON配置格式问题:
环境变量冲突:
bash复制# 错误的变量名(大小写敏感)
export playwright_browser=chromium
# 正确的变量名
export PLAYWRIGHT_BROWSER=chromium
浏览器安装验证:
bash复制# 检查已安装的浏览器
npx playwright install --dry-run
# 安装特定浏览器
npx playwright install chromium
为确保脚本在Windows/Linux/Mac上行为一致,建议:
conftest.py中添加平台检查:python复制import platform
@pytest.fixture(scope="session")
def browser_type(pytestconfig):
if platform.system() == "Darwin":
return "chromium" # 在Mac上强制使用chromium
return pytestconfig.getoption("--browser") or "chromium"
dockerfile复制FROM mcr.microsoft.com/playwright:v1.28.0-focal
WORKDIR /tests
COPY . .
CMD ["npm", "test"]
在调试浏览器选择问题时,可以启用Playwright的调试日志:
python复制import os
os.environ['DEBUG'] = 'pw:api' # 启用API调用日志
os.environ['PLAYWRIGHT_BROWSER'] = 'chromium' # 显式覆盖
with sync_playwright() as p:
browser = p.chromium.launch()
日志会显示浏览器选择的全过程,帮助定位问题。
针对不同测试需求,可以调整启动参数:
python复制browser = p.chromium.launch(
headless=False,
args=[
'--disable-blink-features=AutomationControlled',
'--start-maximized'
],
ignore_default_args=['--enable-automation']
)
对于需要跨浏览器测试的场景,推荐使用以下模式:
python复制import pytest
@pytest.mark.parametrize("browser_type", ["chromium", "firefox"])
def test_example(browser_type):
with sync_playwright() as p:
browser = getattr(p, browser_type).launch()
page = browser.new_page()
# 测试逻辑
browser.close()
我在实际项目中发现,保持浏览器选择逻辑的显式和一致是避免这类问题的关键。特别是在团队协作环境中,建议在项目README中明确记录浏览器选择策略,并在CI流水线中设置强制检查。